• 【Codeforces Round #645 (Div. 2) F】 Tasty Cookie


    题目链接

    【题目翻译】

    给你两个长度都为n的正整数数组,让你把A数组通过两种操作变成B数组。 支持的两种操作: 1.R操作:把A数组翻转。 2.P操作:把A数组变成A数组的前缀和数组,即a[i]=∑a[j] (1<=j<=i)。 如果P操作的次数超过2*10^5,则不用输出操作序列(只需输出第二种操作个数就行),否则输出所有的操作序列

    【题解】

    因为P操作是求前缀和操作,而且两个数组中每个数字最少是1。

    所以如果数组比较大的话,实际上加几次,最后一个数字就会很快变得特别大(超过10^12)。

    (越长的话,P操作次数只会越小)。

    题目作者作了张图,其中t是P操作的上限次数,可以感受一下。

    这有什么用呢?

    大家不要顺着题目的想法,每次都从A变换到B,实际上我们可以反过来想,怎么样才能从B变换到A呢。

    考虑这里的P操作,因为是求A数组的前缀和,且A中每个数字都是大于0的,所以得到的B数组肯定是递增的。

    并且,我们会发现,B数组也可以反过来求出A数组,a[i]=b[i]-b[i-1]

    那么我们就有一个思路了,如果B数组不是严格递增的(相等的话a对应位置就是0了),那么它肯定不是由前缀和操作得来的。

    所以,此时,如果B是严格递减的,那么还有希望,我们可以把它倒转一下,否则,如果不是严格递减也不是严格递增,并且和A还不相同。那么肯定是无解了。

    如果是严格递增(减),并且和A还不一样,那么你有什么办法呢?肯定是做一次前缀和逆操作了。

    所以,对于该题我们就有了一个完整的做法了:

    1.如果B等于A的逆或者A,那么就找到合法的操作序列了,否则转第二步。

    2.如果B是严格递增的,那么对B求一个前缀和的逆操作,否则转第三步。

    3.如果B是严格递减的,那么对B数组求反,否则转第四步。

    4.无解。

    前缀和逆操作的个数就和上面那张图的每个t对应。时间复杂度为O(nans),且ans肯定是小于等于2t的,因为最坏情况就是每次求完逆前缀和,然后翻转一下。

    上面那张图也能看出来,n2t的话,除了n=2的情况,都是可以在时间限制内出解的。

    因此,我们对于n=2的情况,需要单独处理一下

    对于n=2的情况,我们可以先把两个数组升序排一下(输出序列的时候考虑一下就行)

    ①然后,判断a[1]是否和b[1]相等,如果相等,则只需要看看b[2]减去多少次b[1]能够变成a[2],可以变成a[2]的话,就有解,输出即可。但是如果不能通过减去b[1]变成a[2],则无解。

    ②如果a[1]和b[1]不相等,则我们肯定是会一直对b数组进行逆前缀和操作的,但实际上我们可以加速这个过程,因为对b数组进行逆前缀和操作的最后结果就是,b数组变成
    [b[1],b[2]%b[1]],因此,只要b[2]在一直减b[1]的过程中,不会变成a[2],那么我们就直接让它变成这个[b[1],b[2]%b[1]]的状态(累加需要进行的P操作次数),然后reverse一下(B又变成升序的了)
    ,再重复①过程。

    这就是大体的思路,注意在操作过程中,我们是倒着做的,所以进行P操作,R操作,都是倒着来的。应该压入栈中,然后再一个一个弹出来输出答案。
    (超过2E5的情况,可以在压入栈的时候,顺便查一下栈内元素个数是否超过界限。)

    【代码】

    #include<bits/stdc++.h>
    #define ll long long
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%I64d",&x)
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    using namespace std;
    
    const int N = 2e5;
    
    int n;
    ll a[N+10],b[N+10];
    
    //B=A
    bool equals(ll a[],ll b[]){
        rep1(i,1,n) if (a[i]!=b[i]) return false;
        return true;
    }
    
    //B=_reverse(A)
    bool equals_reverse(ll a[],ll b[]){
        rep1(i,1,n) if (a[i]!=b[n-i+1]) return false;
        return true;
    }
    
    vector<char> ans;
    ll cnt_p2 = 0;
    
    void _add(ll cnt,char key){
        if (key=='P'){
            cnt_p2+=cnt;
        }
        if (cnt_p2>N) return;
        for (int i = 1;i <= cnt;i++){
            ans.push_back(key);
        }
    }
    
    int main(){
        //cout<<(1LL<<62)<<endl;
        #ifdef LOCAL_DEFINE
            freopen("D:\rush.txt","r",stdin);
        #endif
        ios::sync_with_stdio(0),cin.tie(0);
        cin >> n;
        rep1(i,1,n) cin >> a[i];
        rep1(i,1,n) cin >> b[i];
        if (n==1){
            if (a[1]==b[1]){
                cout<<"SMALL"<<endl;
                cout<<0<<endl;
                cout<<""<<endl;
            }else{
                cout<<"IMPOSSIBLE"<<endl;
            }
        }else if (n==2){
            int flag1 = a[1]>a[2]?1:0;
            if (a[1]>a[2]) swap(a[1],a[2]);
    
            int flag2 = b[1]>b[2]?1:0;
            if (b[1]>b[2]) swap(b[1],b[2]);
    
            if (equals(a,b)){
                if (flag1+flag2==2){
                    cout<<"SMALL"<<endl;
                    cout<<0<<endl;
                    cout<<""<<endl;
                }
                if(flag1+flag2==1){
                    cout<<"SMALL"<<endl;
                    cout<<1<<endl;
                    cout<<"R"<<endl;
                }
                if (flag1+flag2==0){
                    cout<<"SMALL"<<endl;
                    cout<<0<<endl;
                    cout<<""<<endl;
                }
            }else{
                if (flag2) _add(1,'R');
                ll cnt = 0;
                while (1){
                    if (a[1]==b[1]){
                        if (a[2]>b[2]){
                            cout<<"IMPOSSIBLE"<<endl;
                        }else{
                            if ((b[2]-a[2])%b[1] == 0){
                                cnt += (b[2]-a[2])/b[1];
                                _add((b[2]-a[2])/b[1],'P');
                                if (flag1) _add(1,'R');
                                if (cnt>(long long)2e5){
                                    cout<<"BIG"<<endl;
                                    cout<<cnt<<endl;
                                }else{
                                    cout<<"SMALL"<<endl;
                                    cout<<(int)ans.size()<<endl;
                                    while (!ans.empty()){
                                        cout<<ans.back();
                                        ans.pop_back();
                                    }
                                }
                            }else{
                                cout<<"IMPOSSIBLE"<<endl;
                            }
                        }
                        break;
                    }else{
                        //a[1]!=b[1]
                        //b[1],b[2]%b[1]
                        ll tcnt = (b[2]-(b[2]%b[1]))/b[1];
                        cnt+=tcnt;
                        _add(tcnt,'P');
                        _add(1,'R');
                        b[2] = b[2]%b[1];
                        swap(b[1],b[2]);
                        if (b[1]==0){
                            cout<<"IMPOSSIBLE"<<endl;
                            break;
                        }
                    }
                }
            }
        }else {
            //n>3
            ll cnt = 0;
            while (1){
                if (equals(a,b) || equals_reverse(a,b)){
                    if (equals_reverse(a,b) && !equals(a,b)) ans.push_back('R');
                    if (cnt>N){
                        cout<<"BIG"<<endl;
                        cout<<cnt<<endl;
                    }else{
                        cout<<"SMALL"<<endl;
                        cout<<(int)ans.size()<<endl;
                        while (!ans.empty()){
                            cout<<ans.back();
                            ans.pop_back();
                        }
                    }
                    break;
                }else{
                    int cntz = 0,cntf = 0,cnt0 = 0;
                    rep1(i,2,n){
                        if (b[i]-b[i-1]==0){
                            cnt0++;
                        }else if (b[i]-b[i-1]>0){
                            cntz++;
                        }else cntf++;
                    }
                    if (cntz==n-1){ //ascn
                        _add(1,'P');
                        rep2(j,n,2) b[j] = b[j]-b[j-1];
                        cnt++;
                    }else if (cntf==n-1){//desc
                        reverse(b+1,b+1+n);
                        _add(1,'R');
                    }else {
                        cout<<"IMPOSSIBLE"<<endl;
                        break;
                    }
                }
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    boot.asm
    C talk
    C 数据类型
    Locks, Deadlocks, and Synchronization
    C++的RTTI 观念和用途
    setup.asm
    驱动对象设备对象设备栈
    JNI 内存泄漏
    KMP 字符串匹配算法
    解开 Windows 下的临界区中的代码死锁
  • 原文地址:https://www.cnblogs.com/AWCXV/p/13046690.html
Copyright © 2020-2023  润新知