题目
给你一个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;
}