Codeforces Round #645 (Div. 2) F.Tasty Cookie(思維題/分類討論)

題目

給你一個n(n<=2e5),一個A數組,一個B數組(1<=Ai,Bi<=1e12)

你可以對A數組進行兩種操作,

①反轉A數組,記爲R操作

②對A數組做前綴和,即[A1,A2,...]->[A1,A1+A2,...],記爲P操作

問A能否變成B,如果不能輸出IMPOSSIBLE

否則,

若P操作超過2e5次,輸出BIG,以及P操作的次數

P操作沒超過2e5次,輸出SMALL,R和P的操作總數,以及R和P的操作序列

思路來源

http://www.360doc.com/content/20/0604/21/13328254_916532267.shtml

qls代碼

題解

考慮到一個長度爲3的1 1 1數組,做前綴和n次,第二項是O(n)級的,第三項是O(n^2)級的,

這樣大致1e6次操作就能到1e12了,所以n>3的可暴力

暴力的時候,發現a到b也不好做,

考慮如何b逆推回a,因爲做完前綴和之後的數組肯定是增序的,這樣就可以差分回去了

先檢查a和b是否完全一致,a和b的逆序是否完全一致,一致直接返回

否則,如果b是嚴格增序(因爲沒有0)或降序的,說明經歷了一次前綴和或前綴和加一次反轉

那麼如果是增序的,就差分一次,再判斷

n=1顯然可以特判,考慮n=2怎麼做

 

n=2,也在每步之前,判一下a和b是否完全一致,a和b的逆序是否完全一致,一致直接返回,

否則,不妨設b[1]<b[2](大於先R一次),考慮其與min(a[1],a[2])和max(a[1],a[2])的關係,

若b[1]<min(a[1],a[2]),顯然無法再通過差分得到

若b[1]=min(a[1],a[2]),說明已經對齊,此時b[2]如果能減去b[1]若干次得到max(a[1],a[2])就是Yes,否則No

若b[1]>min(a[1],a[2]),說明最小值還沒達到,那就可以加速這個b[2]不斷減b[1]的過程,得到(b[1],b[2]%b[1])後再考慮

實際實現的時候,考慮b[2]可能是b[1]的倍數,但是b[2]不該變成0(因爲序列裏沒有0)

因此會給b[2]留一點,b[2]-=((b[2]-1)/b[1]*b[1]),這樣b[2]就最少是1了

設t=b[2]減掉的b[1]的倍數,如果某一步t<=0,說明本次操作不可減/什麼都沒減,顯然不合法

代碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define sci(a) scanf("%d",&(a))
int n;
ll a[N+5],b[N+5],cntp;
string res;
void out(bool x){
    if(!x)puts("IMPOSSIBLE");
    else{
        if(cntp>N){
            puts("BIG");
            printf("%lld\n",cntp);
        }
        else{
            puts("SMALL");
            reverse(res.begin(),res.end());
            printf("%d\n%s\n",(int)res.size(),res.c_str());
        }
    }
}
bool ok(){
    bool sm=1;
    rep(i,1,n){
        sm&=(a[i]==b[i]);
    }
    if(sm)return 1;
    sm=1;
    rep(i,1,n){
        sm&=(a[i]==b[n+1-i]);
    }
    if(sm){
        if(cntp<=N){
            res+='R';
        }
        return 1;
    }
    return 0;
}
bool solve2(){
    ll x=min(a[1],a[2]),y=max(a[1],a[2]);
    while(1){
        if(ok())return 1;
        if(b[1]<b[2]){
            ll t=0;
            if(b[1]<x){
                return 0;
            }
            else if(b[1]==x){//如果最小值已經對齊
                t=(b[2]-y)/b[1];//b[2]->y(令b2至少爲y,嘗試令最大值對齊)
            }
            else{
                t=(b[2]-1)/b[1];//b[2]->(b[2]%b[1])(且令b2至少爲1)
            }
            if(t<=0){//已經不能進行這樣的操作了
                return 0;
            }
            else{
                b[2]-=t*b[1];
                if((cntp+=t)<=N){
                    res+=string(t,'P');
                }
            }
        }
        else if(b[1]>b[2]){
            swap(b[1],b[2]);
            if(cntp<=N){
                res+='R';
            }
        }
        else{
            return 0;
        }
    }
}
bool solve3(){
    while(1){
        if(ok())return 1;
        bool u=1,d=1;//up down
        rep(i,1,n-1){
            u&=(b[i]<b[i+1]);
            d&=(b[i]>b[i+1]);
        }
        if(u){
            per(i,n,2){
                b[i]-=b[i-1];
            }
            if((++cntp)<=N){
                res+='P';
            }
        }
        else if(d){
            reverse(b+1,b+n+1);
            if(cntp<=N){
                res+='R';
            }
        }
        else{
            return 0;
        }
    }
}
int main(){
    sci(n);
    rep(i,1,n)scanf("%lld",&a[i]);
    rep(i,1,n)scanf("%lld",&b[i]);
    if(n==1)out(a[1]==b[1]);
    else if(n==2)out(solve2());
    else out(solve3());
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章