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 }

 

posted @ 2018-10-23 16:36  menhera  阅读(454)  评论(0编辑  收藏  举报