【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;
}

原文地址:https://www.cnblogs.com/AWCXV/p/13046690.html