Codeforces1065G Fibonacci Suffix 【递推】【二分答案】
题目分析:
首先为了简便起见我们把前$15$的答案找出来,免得我们还要特判$200$以内之类的麻烦事。
然后我们从$16$开始递推。考虑猜测第i位是$0$还是$1$(这本质上是个二分)。一开始先猜是$1$,然后求是$0$的有多少个,与当前的$k$判断确认$0$和$1$。
然后考虑到某种情况就不输出的情况,实际上就是末尾的这个$ans$正好合法。
然后递推的时候除了将两个串原本出现的加起来,还要考虑拼接的时候多出的。可以预处理也可以边$dp$边做。
不预处理的暴力做时间是$O(mn^3)$(过不了)
预处理的暴力做是$O(mn^2)$
不预处理的KMP是$O(mn^2)$
预处理的KMP是$O(mn)$。
自行选择。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n,m;long long k; 5 6 string str[17],suf[2010]; 7 8 long long f[250],d[250],h[250],qy[2][2]; 9 string p[2],s[2]; 10 string ans; 11 12 int cmp(string alpha,string beta){ 13 for(int i=0;i<min(alpha.length(),beta.length());i++){ 14 if(alpha[i] == beta[i]) continue; 15 if(alpha[i] < beta[i]) return 1; 16 else return 0; 17 } 18 return alpha.length()<beta.length(); 19 } 20 21 int Try(string a){ 22 int res = 0; 23 for(int i=0;i<a.length();i++){ 24 if(i+ans.length()-1 >= a.length()) break; 25 int flag = true; 26 for(int j=0;j<ans.length();j++){ 27 if(a[i+j] != ans[j])flag = false; 28 } 29 res += flag; 30 } 31 return res; 32 } 33 34 long long solve(){//200 35 //match 200*200 36 int len = ans.length(); 37 memset(d,0,sizeof(d)); 38 memset(h,0,sizeof(h)); 39 memset(qy,0,sizeof(qy)); 40 p[0].clear();p[1].clear();s[0].clear();s[1].clear(); 41 d[14] = h[14] = 0; d[15] = h[15] = 1; 42 for(int i=0;i<len-1;i++) p[0].push_back(str[14][i]),p[1].push_back(str[15][i]); 43 for(int i=1;i<=len-1;i++) s[0].push_back(str[14][str[14].length()-len+i]); 44 for(int i=1;i<=len-1;i++) s[1].push_back(str[15][str[15].length()-len+i]); 45 for(int i=0;i<2;i++) for(int j=0;j<2;j++) qy[i][j] = Try(p[i]+s[j]); 46 47 f[14] = Try(str[14]); f[15] = Try(str[15]); 48 49 for(int i=16;i<=n;i++){//200 50 h[i] = h[i-1]; //suf 51 d[i] = d[i-2]; //pre 52 f[i] = f[i-1]+f[i-2]; 53 f[i] += qy[d[i]][h[i]]; 54 if(f[i] > 1e18) return f[i];//return now 55 } 56 return f[n]; 57 } 58 59 int main(){ 60 scanf("%d%lld%d",&n,&k,&m); 61 str[0] = "0"; str[1] = "1"; 62 for(int i=2;i<=15;i++) str[i] = str[i-2]+str[i-1]; 63 if(n <= 15){ 64 for(int i=0;i<str[n].length();i++){ 65 for(int j=i;j<str[n].length();j++) suf[i+1].push_back(str[n][j]); 66 } 67 sort(suf+1,suf+str[n].length()+1,cmp); 68 for(int i=0;i<min(m,(int)suf[k].length());i++) printf("%c",suf[k][i]); 69 return 0; 70 }else{ 71 for(int i=1;i<=m;i++){ 72 ans.push_back('0'); 73 long long z = solve(); 74 if(z < k){ k -= z; ans.pop_back(); ans.push_back('1'); } 75 int flag = 1; 76 for(int i=suf[n].length()-ans.length(),j=0;i<suf[n].length();i++){ 77 if(ans[j] != suf[n][i]) flag = false; 78 j++; 79 } 80 k -= flag; 81 if(k == 0){ 82 for(int i=0;i<ans.length();i++) printf("%c",ans[i]); 83 return 0; 84 } 85 } 86 for(int i=0;i<ans.length();i++) printf("%c",ans[i]); 87 } 88 89 return 0; 90 }