CA那里有没有翻译的,本弱菜秉承着看不懂英文的原则翻译了一下(渣翻勿喷
解决我们的这个任务,需要先解决一个更复杂的问题:我们对序列的第i个元素我们声明一个元素Ai
Ai是第i位元素必须含有的数位
对于我们最初的任务,Ai={di} (译者注:di是读进来的那个)
让N=(X)y y是x%10(也就是N的最后一位),X=N/10 (译者注:N=X*10+Y)
当我们确定y的一个可能的值过后,序列会变成这样:(X)y (X)y+1 .... (X)8 (X)9 (X+1)0 (X+1)1 ... (X+1)8 (X+1)9 (X+2)0
我们移去最后一位,我们得到序列X ... X X+1 ... X+1 ... X+2 ...
什么数字是X必须含有的呢?
(X)y含有A1 X必须含有A1/{y} (X)y+1含有A2 X必须含有A2/{y+1} 等等都是这样
合并这些需求,我们就可以得到一个新的序列B_1, B_2, …
B_1 是 X 必须拥有的, B_2 是 X+1 必须拥有的 等等都是这样
我们对B序列做相同的事情
做了相同的事情会发生什么呢?
每次操作,序列长度为原来的最多[k/10]+1
递归到长度为1,2的时候就可以统计答案了
时间复杂度O(k*logk)
上面是英文翻译,mdzz歪果仁完全没有说到重点啊!!
现在对每个数维护一个域Ai
Ai是一个为一个二进制数,第j位为1表示N+i-1必须含有j这个数
让N=(X)y y是x%10(也就是N的最后一位),X=N/10 (译者注:N=X*10+Y)
当我们确定y的一个可能的值过后,序列会变成这样:(X)y (X)y+1 .... (X)8 (X)9 (X+1)0 (X+1)1 ... (X+1)8 (X+1)9 (X+2)0
现在考虑从低位向高位枚举每一位
枚举这一位从什么数字地方开始,然后暴力验证哪些A[i]已经满足要求了
把没有满足要求的存到一个数组里面递归求下一位
复杂度O(k)=10*O(k/10)+n
感谢bzoj id 为 zzzong的同学纠正错误:如果当前答案为000,并且是合法的,那么最终用1000更新答案
要改正这个错误,就把所有位是0的情况特判掉就好了
//Copyright(c)2016 liuchenrui #include<bits/stdc++.h> #define LL long long using namespace std; inline void splay(int &v){ v=0;char c=0;int p=1; while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();} while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();} v*=p; } LL solve(int *a,int n,int can9,bool all0){ if(n==1){ LL ret=0;int p=a[1]; for(int i=1;i<=9;i++){ if(p&(1<<i)){ ret=ret*10+i; if(ret<10&&(p&1))ret*=10; } } if(!ret&&(p&1))ret=10; if(!ret&&all0)return 1; return ret; } int *tn=new int[n/10+20];LL ret=1000000000000000000LL; for(int i=0;i<=9;i++){ if(i==9&&!can9)break; int t=0,now=i,num=0,flag=0; for(int j=1;j<=n;j++){ num|=(a[j]&(1023-(1<<now))); if(!now&&(a[j]&1))flag=1; now++;if(now>=10)now-=10; if(!now||j==n)tn[++t]=num,num=0; } LL x=solve(tn,t,n>2||i<9,all0&&(i==0))*10+i; if(!x&&flag)x=10; ret=min(ret,x); } return ret; } int a[100010]; int main(){ freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); int n;splay(n); for(int i=1;i<=n;i++){ splay(a[i]);a[i]=1<<a[i]; } cout<<solve(a,n,1,1)<<endl; }