2009 Multi-University Training Contest Part 7 Supplementary Questions

Keywords: iOS less REST Programming

2009 Multi-University Training Contest Part 7 Supplementary Questions

The game was organized by three people. During the game, I felt I didn't give much, so I added a question. And I always feel tired in the end of the game, hoping to change.

- Splitting Line

These five questions have been filled up for two days.

1001: A + B = C (simulation + thought)

Meaning: a 10x+b 10y=c 10z and 0 < x,y,z < 106. a 10^x+b 10^y=c 10 ^ Z ~ and 0 < x,y,z < 10 ^ 6. a 10x+b y = C 10z and < 0 < x,y,z < 106. Solve x,y,z, y, z, z, z, y, z, y, y

Solution 1: First remove the zero at the end of a, B and C. Then we can get a new number of a, B and C. After we have solved the problem, we can get a new number of a, B and C.

We consider the source of the highest position of the number c. There are two possible sources of the highest position of the number c. The first is the direct addition of the highest bits of a or b (including the case where the one of a or b is zero), and the other is the addition of the highest bits of a and b by carry.

For the first one, we let one of c and a and b add zero to the same place first, and then judge whether the 10 power of the other number can be obtained after subtraction.

For the second kind, let c be one more than a, and judge whether the 10 power of another number can be obtained after subtraction.

Code:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e5+20;
const ll mod=1e9+7;
char a[N],b[N],c[N];
char sa[N],sb[N],sc[N];
int la,lb,lc;
int take_a,take_b,take_c;
int x,y,z;
char ans[N];
bool check1(char c[],int lc,char a[],int la,char b[],int lb)
{
    strcpy(sc,c);
    strcpy(sa,a);
    strcpy(sb,b);
    int ml=max(lc,la);
    for(int i=lc; i<ml; ++i) sc[i]='0';
    sc[ml]='\0';
    for(int i=la; i<ml; ++i) sa[i]='0';
    sa[ml]='\0';
    if(strcmp(sc,sa)< 0 ) return false;
    /*Large number subtraction*/
//    printf("sc:%s,sa:%s\n",sc,sa);
    reverse(sc,sc+ml);
    reverse(sa,sa+ml);
    mset(ans,0);
    for(int i=0; i<ml; ++i)
    {
        ans[i]+='0'+sc[i]-sa[i];
        if(ans[i]<'0')
        {
            ans[i]+=10;
            sc[i+1]--;
        }
    }
    int p=ml-1;
    while(p>0&&ans[p]=='0') --p;
    reverse(ans,ans+p+1);
    ans[p+1]='\0';
//     printf("ans:%s\n",ans);
//    bool flag=true;
    if(p+1<lb) return false;
    for(int i=lb; i<=p; ++i)
    {
        if(ans[i]!='0') return false;
    }
    ans[lb]='\0';
    if(strcmp(ans,sb)==0)
    {
        x=ml-lc;
        y=ml-la;
        z=p+1-lb;
        return true;
    }
    else
        return false;
}
bool check2(char c[],int lc,char a[],int la,char b[],int lb)/*c The highest bit obtained by carry.*/
{
    strcpy(sc,c);
    strcpy(sa,a);
    strcpy(sb,b);
    int ml=max(lc,la);
    for(int i=lc; i<=ml; ++i) sc[i]='0';
    sc[ml+1]='\0';
    for(int i=la; i<ml; ++i) sa[i]='0';
    sa[ml]='\0';
    /*Large number subtraction*/
//    printf("sc:%s,sa:%s\n",sc,sa);
    reverse(sc,sc+ml+1);
    reverse(sa,sa+ml);
    mset(ans,0);
    for(int i=0; i<ml; ++i)
    {
        ans[i]+='0'+sc[i]-sa[i];
        if(ans[i]<'0')
        {
            ans[i]+=10;
            sc[i+1]--;
        }
    }
    int ans_len=ml;
    if(sc[ans_len]>'0')
    {
        ans[ans_len++]=sc[ml];
    }
    while(ans_len>0&&ans[ans_len-1]=='0') --ans_len;
    reverse(ans,ans+ans_len);
//    ans[ans_len]='\0';
//    printf("ans:%s\n",ans);
//    bool flag=true;
    if(ans_len<lb) return false;
    for(int i=lb; i<ans_len; ++i)
    {
        if(ans[i]!='0') return false;
    }
    ans[lb]='\0';
    if(strcmp(ans,sb)==0)
    {
        x=ml-lc+1;
        y=ml-la;
        z=ans_len-lb;
        return true;
    }
    else
        return false;
    /*Next, determine whether the string sc is the prefix of ans*/
}
void solve(int add_a,int add_b,int add_c)
{
    add_a-=take_a;
    add_b-=take_b;
    add_c-=take_c;
    int add=0;
    if(add_a<0&&-add_a>add) add=-add_a;
    if(add_b<0&&-add_b>add) add=-add_b;
    if(add_c<0&&-add_c>add) add=-add_c;
    printf("%d %d %d\n",add_a+add,add_b+add,add_c+add);
}
int main()
{
//    ios::sync_with_stdio(false);cin.tie(0);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        take_a=take_b=take_c=0;
        scanf("%s%s%s",a,b,c);
        la=strlen(a);
        lb=strlen(b);
        lc=strlen(c);
        while(la>0&&a[la-1]=='0') --la,++take_a;
        a[la]=0;
        while(lb>0&&b[lb-1]=='0') --lb,++take_b;
        b[lb]=0;
        while(lc>0&&c[lc-1]=='0') --lc,++take_c;
        c[lc]=0;
//        printf("chedan_%d %d %d\n",take_a,take_b,take_c);
        if(check1(c,lc,a,la,b,lb))//x,y,z
        {
            solve(y,z,x);
            continue;
        }
        if(check1(c,lc,b,lb,a,la))//x,y,z
        {
            solve(z,y,x);
            continue;
        }
        else
        {
            if(check2(c,lc,a,la,b,lb))//
            {
                solve(y,z,x);
                continue;
            }
            if(check2(c,lc,b,lb,a,la))//x,y,z
            {
                solve(z,y,x);
                continue;
            }
            //Untreated
        }
        printf("-1\n");
    }
    return 0;
}

Solution 2:

Firstly, the end of a,b,ca,b,ca,b,c is removed, and C_10kC*10^kC_10k is considered.

In the case of K > 0, only A+B=C 10kA+B=C*10^kA+B=C 10k exists. Because assuming that A 10n+B=C 10kA * 10 ^ n + B = C 10 ^ kA 10n+B=C 10k is always unsatisfactory, the final position of the result must be non-zero, which contradicts the hypothesis.

The rest is k=0k=0k=0, where only $A*10^n+B=C $.

Solution 222 has been working all morning and has been running out of time. Finally, it is found that for loop +i I I is written as +i+i.

Code:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const int N=1e5+10;
string add(string a,string b)
{
    reverse(a.begin(),a.end());reverse(b.begin(),b.end());
    int maxl=max(a.size(),b.size());
    for(int i=a.size();i<maxl;++i) a.append("0");
    for(int i=b.size();i<maxl;++i) b.append("0");
    for(int i=0;i<maxl;++i){
        b[i]+=a[i]-'0';
        if(b[i]>'9'){
            b[i]-=10;
            if(i==maxl-1){
                b.append("1");
            }
            else
                b[i+1]++;
        }
    }
    reverse(b.begin(),b.end());
    return b;
}
string mul(string a,string b)//The requirement is a-b// where the function name should be written as sub...
{
     reverse(a.begin(),a.end());reverse(b.begin(),b.end());
     int maxl=a.size();
     for(int i=b.size();i<maxl;++i) b.append("0");
     for(int i=0;i<maxl;++i)
     {
         a[i]-=b[i]-'0';
         if(a[i]<'0'){
            a[i]+=10;
            a[i+1]-=1;
         }
     }
     while(a.size()>1&&a[a.size()-1]=='0') a.pop_back();
    reverse(a.begin(),a.end());
   return a;
}
int add_a,add_b,add_c;
int take_a,take_b,take_c;
bool check1(string &a,string& b,string &c)//Calculating the Tenth Power of K in a+b=c*k
{
    string ans=add(a,b);
    if(ans.size()<c.size()||(ans.size()==c.size()&&ans<c)) return false;
    int cnt=0;
    for(int i=c.size();i<ans.size();++i) {
        if(ans[i]!='0') return false;
        ++cnt;
    }
    for(int i=0;i<c.size();++i){
        if(ans[i]!=c[i]) return false;
    }
    add_a=add_b=0;
    add_c=cnt;
    return true;
}
bool check2(string &a,string &b,string &c)
{
    if(c.size()<b.size()||(c.size()==b.size()&&c<b)) return false;
    string ans=mul(c,b);
    int cnt=0;
    for(int i=a.size();i<ans.size();++i) {
        if(ans[i]!='0') return false;
        ++cnt;
    }
    for(int i=0;i<a.size();++i){
        if(ans[i]!=a[i]) return false;
    }
    add_a=cnt;
    add_b=0;
    add_c=0;
    return true;
}
void solve(int add_a,int add_b,int add_c)
{
    add_a-=take_a;
    add_b-=take_b;
    add_c-=take_c;
    int add=0;
    if(add_a<0&&-add_a>add) add=-add_a;
    if(add_b<0&&-add_b>add) add=-add_b;
    if(add_c<0&&-add_c>add) add=-add_c;
    cout<<add_a+add<<" "<<add_b+add<<" "<<add_c+add<<endl;
//    printf("%d %d %d\n",add_a+add,add_b+add,add_c+add);
}
string a,b,c;
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        take_a=take_b=take_c=0;
        cin>>a>>b>>c;
        while(a.size()>1&&a[a.size()-1]=='0'){
            take_a++;
            a.pop_back();
        }
        while(b.size()>1&&b[b.size()-1]=='0'){
            take_b++;
            b.pop_back();
        }
        while(c.size()>1&&c[c.size()-1]=='0'){
            take_c++;
            c.pop_back();
        }
        if(check1(a,b,c))
        {
            solve(add_a,add_b,add_c);
            continue;
        }
        else if(check2(a,b,c))
        {
            solve(add_a,add_b,add_c);
            continue;
        }
        else if(check2(b,a,c))
        {
            solve(add_b,add_a,add_c);
            continue;
        }
        else
            cout<<"-1"<<endl;
    }
    return 0;
}

1006: Final Exam

That's the question. Let me make up for it one day and one night.

** Question Implication: ** There are n questions in total. We need to do the right k questions. We only know the total score of n questions is m, and we don't know the distribution of the scores. If a question is X, it will take x+1 time to review. Ask at least how long it takes for you to review, so that you can surely pass k questions.

Thought: If I were a teacher, I would card you to review the minimum subject n-k+1 in the textbook. For example, now there are five courses review time is 0.1,234, to pass three, then the teacher with the least score card you only need to card at least the first three, will make the five courses score is 0.12***,* on behalf of the course score casually, give 0 is also OK.

So let's switch back to the student's point of view. If we let him have at most n-k courses, we can make the total time for the first n-k+1 course be m+1. The remaining k-1 course left him with no choice. If he only chooses the first n-k+1 gate, then one of them will not be stuck. So how does it make him not want to take K-1 after that? Assuming that the time of each course in the latter k-1 course is t, then we only need m(n_k)t< tm-(n-k)*t< tm(n_k)t<t.

The formula above means: the first 1, 2,... The review time of n-k courses is set to t, and the last course can only be less than t, so that he will not choose k-1 courses.

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ll n,m,k;
        scanf("%lld%lld%lld",&n,&m,&k);
        ll t=m/(n-(k-1))+1;
        printf("%lld\n",t*(k-1)+m+1);
    }
    return 0;
}

1007: Getting Your Money Back (Dynamic Programming + Monotonic Optimization)

This problem is because you can't understand the problem solution, but because the problem solution produces another DP thought. wa 20 rounds from beginning to end, find bug s for less than 6 hours. Write down the mistakes you made and remind yourself!

1. The boundary problem is not considered clearly. (For example, when p is used as a pointer for monotonicity, P should start from 1 and be written as 0 at the beginning, or if DP [0] [0] [0] DP [0] [0] [0] [0] does not exist, the value should be set as invalid.)

2. Not considering the situation clearly and carelessly.

3. At first, I don't believe in myself. I always want to solve problems. Facts have proved that there are many ways of thinking, and dp has been used thousands of times.

Completion time: 0:20 a.m. on August 16, 2019

Topic:

** Thoughts: ** The ideas here are different from the solutions.

We can see that the relationship between answer and interval can be classified as the relationship between answer and interval length. But there are two different states for interval length, one is that the left endpoint can definitely withdraw money, the other is that the left endpoint may not necessarily withdraw money.

We use dp[0][i]dp[0][i]dp[0][i] DP [0] [i] to denote the interval of length iii, and the left endpoint must be able to withdraw money, which in the worst case determines the minimum cost gold coin that has been withdrawn all the money.

Then dp[1][i]dp[1][i]dp[1][i] DP [1] [i] denotes the interval of length iii, and the left endpoint may not be able to withdraw money. In the worst case, it determines the minimum cost gold coin that has been withdrawn all the money.

For the special case of 1000 points, we can convert the minimum cost of [0,r][0,r][0,r] into dp[1][r]dp[1][r]dp[1][r] dp[1][r]dp[1][r]dp[1][r] DP [1] [r] DP [1] [r] [r] DP [1] [r] DP [1] [r] when the length of the interval is 0.

For other intervals [l,r] [l,r] [l,r], we only need dp[0][r_l+1] dp[0][r-l+1] dp[0][r_l+1] [0] [r_l+1].

dp equation:

dp[0][x]=min(max(dp[1][x−j]+a,dp[0][j−1]+b)),j∈[1,x]dp[0][x]=min(max(dp[1][x-j]+a,dp[0][j-1]+b)) ,j\in[1,x]dp[0][x]=min(max(dp[1][x−j]+a,dp[0][j−1]+b)),j∈[1,x]

dp[1][x]=min(max(dp[1][x−j]+a,dp[1][j−1]+b)),j∈[1,x]dp[1][x]=min(max(dp[1][x-j]+a,dp[1][j-1]+b)) ,j\in[1,x]dp[1][x]=min(max(dp[1][x−j]+a,dp[1][j−1]+b)),j∈[1,x]

Because enumeration length 1 in dp[0][x]dp[0][x]dp[0][x] DP [0] [x] state must be successful, there is no failure, which is also the reason why DP [0] [0] [0] DP [0] [0] value is invalid.

But the naive idea is that O(n) enumeration of endpoints is needed every time, and the time complexity O(n^2).

Feel like the next paragraph of a blog said well, here quote. Source Blog Address

Obviously, the larger the span of the interval is, the higher the cost will be. The dp[0[i]dp[0[i]dp[0[i] DP [0 [i] and dp[1][i]dp[1][i]dp[1][i] are monotonous. Then considering the transfer equation, we can predict that the cost will decrease first and then increase as the decision point jjj moves from left to right. Therefore, we can consider directly dividing the transfer equation into three parts to find the smallest decision in the middle. However, the theoretical complexity of the first three points can be over, but I did write TLE, of course, it may be my writing disability. (I also TLE three points ()

Code:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const int N=1e5+10;
ll dp[2][200005];
ll t,x,y,a,b;
ll f0(ll i,ll j)
{
    return max(dp[0][j-1]+b,dp[1][i-j]+a);
}
ll f1(ll i,ll j)
{
    return max(dp[1][j-1]+b,dp[1][i-j]+a);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>t;
    dp[0][0]=-1e15;
    dp[1][0]=0;
    while(t--)
    {
        cin>>x>>y>>a>>b;
        dp[0][1]=a;
        dp[1][1]=max(a,b);
        ll ls=y-x+1;
        int flag=0;
        if(x==0)
        {
            --ls;
            flag=1;
        }
        int p0=1,p1=1;
        for(ll i=2;i<=ls;++i){
            /*Find dp[0][i]*/
            while(p0<i&&f0(i,p0)>=f0(i,p0+1)) ++p0;
            dp[0][i]=f0(i,p0);
            while(p1<i&&f1(i,p1)>=f1(i,p1+1)) ++p1;
            dp[1][i]=f1(i,p1);
        }
        if(flag==1)
            cout<<dp[1][ls]<<endl;
        else
            cout<<dp[0][ls]<<endl;//
    }
    return 0;
}

1010: Just Repeat

This question made up for me all morning. It's not really difficult. It's mainly about understanding the meaning of the topic. Here is a record of the mistakes made in the process of filling in the questions.

1. The meaning of the title is not clearly read, mistakenly believing that the color of the card that cannot be played by the opponent last time is actually the color of all the cards that the opponent has played.

2. Considering that O(n*logn) will overtime, I have been thinking about O(n) method, but I did not expect to use unordered_map. It is even more ridiculous to think that the data obtained in the case of p=2 are regular and can be calculated by O(n) (~> < ~).

Completion time: 2019-8-16 12:53

Title: Two people bet on winning or losing by playing games. These two people have n and m cards and cards, and they all know the opponent's cards, each card has a color. The rules of the game are: the two sides take turns to play a card each time, but they can't play the cards of the color that the opponent has played, and the players who can't play the cards first lose (including no cards and no cards). Ask both sides to use the best strategy and who wins in the end.

Thought: This question is actually to calculate who plays the most cards.

Firstly, for cards without duplication of colors, both sides can play without restriction. So we just need to consider the duplicate colors of both sides. If I have X yellow cards, the other party has y cards. Then the contribution of playing yellow card is x, and the contribution of playing yellow card opposite is y.

The next quotation

So far, the question turns to another one: there is a bunch of things, each of which has two values. A gets the benefit of ai, B gets the benefit of bi. Two people take it in turn. Find the respective benefit of two people under the optimal strategy. This is a classic question. The answer is to simulate it according to the order of ai + bi. Now. (Optimal strategy means that the difference between the ultimate value and the opposite value is the greatest. After sorting, we only need to take A and B in turn.

Then QQ cards are the value of QQ cards with duplicate colors plus the number of cards without duplicate colors. CC Similar

Code:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long u64;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const int N=1e5+10;
u64 k1,k2,mod;
unordered_map<u64,int> mmp_q;
unordered_map<u64,int> mmp_c;
unsigned long long rng() {
    unsigned long long k3 = k1, k4 = k2;
    k1 = k4;
    k3 ^= k3 << 23;
    k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    return k2 + k4;
}
u64 repQ,repC,remQ,remC;
u64 card[2][N];
void read(int kinds,int n,int cmd)
{
//    puts("--------");
    if(cmd==1)
        for(int i=0;i<n;++i)
             scanf("%llu",&card[kinds][i]);
    else{
        scanf("%llu%llu%llu",&k1,&k2,&mod);
        for(int i=0;i<n;++i)
            card[kinds][i]=rng()%mod;
    }
}
P reap[N];
int top;//The types of repetition and the corresponding sum
bool cmp(P a, P b)
{
    return a.first+a.second>b.first+b.second;
}
int main()
{
    int t,n,m,cmd;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&cmd);
        read(0,n,cmd);
        read(1,m,cmd);
        repQ=repC=0;
        mmp_q.clear();
        mmp_c.clear();
        for(int i=0;i<n;++i) ++mmp_q[card[0][i]];
        for(int i=0;i<m;++i) ++mmp_c[card[1][i]];
        top=0;
        for(pair<u64,int> p :mmp_q)
        {
            u64 val=p.first;
            int cnt=p.second;
            if(mmp_c.find(val)!=mmp_c.end()){
                int other_cnt=mmp_c[val];
                repQ+=cnt;
                repC+=other_cnt;
                reap[top++]={cnt,other_cnt};
            }
        }
        u64 sum_q=n-repQ,sum_c=m-repC;
        sort(reap,reap+top,cmp);
        for(int i=0;i<top;++i){
            if(i&1){
                sum_c+=reap[i].second;
            }
            else
                sum_q+=reap[i].first;
        }
        if(sum_q>sum_c)
            printf("Cuber QQ\n");
        else
            printf("Quber CC\n");
    }
    return 0;
}

1011: Kejin Player (Simple Probability DP)

** Question Implication: ** There are n n n n n n n grades of 1 1 1 to n n n. When we upgrade from I I I I I to i+1 I + 1 i+1, we need to spend a[i] a[i] a[i] gold coin, and there is a probability that r[i]/r[i] r[i]/r[i] r[i]/r[i]/r[i]/r[i] will be upgraded successfully, otherwise we will fail and fall to x[i] x[i]. What is the expected gold coin from l l to r r r?

** Idea: ** We find that upgrading can only be done in one level. Assuming that f(1,x)f(1,x)f(1,x) f (1, x) f (1, x) is an expected gold coin from 111 to xxx, then the desired gold coin from l l l to r r r is f (1, r)f(1,l) f(1,r) - f(1,l) f (1, r)f(1,l). We use dp[i]dp[i]dp[i] DP [i] to represent the expected gold coin for upgrading from iii to i+1i+1i+1, then there will be

dp[i]=a[i]+(1−p)(dp[i]+dp[i−1]+dp[i−2]...dp[x[i]])dp[i]=a[i]+(1-p)(dp[i]+dp[i-1]+dp[i-2]...dp[x[i]])dp[i]=a[i]+(1−p)(dp[i]+dp[i−1]+dp[i−2]...dp[x[i]])

After we transfer the item, we get it.

dp[i]=(a[i]+(1−p)∗(dp[i−1]+dp[i−2]...dp[x[i]]))/p​dp[i]=(a[i]+(1-p)*(dp[i-1]+dp[i-2]...dp[x[i]]))/p​dp[i]=(a[i]+(1−p)∗(dp[i−1]+dp[i−2]...dp[x[i]]))/p​

Continuity and part of it can be obtained by prefix and O(1)

Therefore, the desired gold coin from l l l to r r r is = dp[l]+dp[l+1]...+dp[r 1]dp[l]+dp[l+1]...+dp[r-1]dp[l]+dp[l+1]...+dp[r 1]

Code:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=5e5+5;
const ll mod=1e9+7;
ll qpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
ll inv(ll a)
{
    return qpow(a,mod-2);
}
ll r[N],s[N],x[N],a[N];
ll sum[N];
int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
        ll n,q;
        scanf("%lld %lld",&n,&q);
        sum[0]=0;
        for(ll i=1;i<=n;++i)
            scanf("%lld%lld%lld%lld",r+i,s+i,x+i,a+i);
        for(ll i=1;i<=n;++i)
        {
            ll p=r[i]*inv(s[i])%mod;
            ll ans=(a[i]+(1ll-p+mod)*((sum[i-1]-sum[x[i]-1]+mod)%mod)%mod)%mod;
            ans=ans*inv(p)%mod;
            sum[i]=(sum[i-1]+ans)%mod;//*****
        }
        while(q--)
        {
            ll l,r;
            scanf("%lld%lld",&l,&r);
            ll ans=(sum[r-1]-sum[l-1])%mod;
            ans=(ans+mod)%mod;
            printf("%lld\n",ans);
        }
    }
    return 0;
}

Posted by arjan.top on Thu, 15 Aug 2019 22:17:53 -0700