题意:
给出一个斐波那契序列,F[0] = “0” , F[1] = “1” , F[i] = F[i - 2] + F[i - 1]. 求第k小的后缀的前m位。
题解
直接按位贪心
每次check一个前缀在F[n]中的出现次数。
这个可以维护pre,suf , num表示F[i]和当前串的前后缀匹配长度和当前串出现次数
长度不够默认可以匹配,用bitset优化合并
复杂度O(n * m * m/32)
注意特判当前串是否作为一个后缀出现,因为总是把后面的串作为后缀,暴力跑200位然后判断即可
还有几个坑点:
出现次数可能很大,会爆longlong,要和inf取min
注意每次check的清空和初始化
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const ll inf = 1e18;
const int N = 220;
const int maxn = 220;
const ll mod = 1e9 + 7;
struct node{
ll num,len;
bitset <N> pre,suf;
node() { num = len = 0; pre.reset(),suf.reset(); }
void clear(){
num = len = 0;
pre.reset() , suf.reset();
}
}f[220];
int fail[maxn];
struct node2{
int len;
int s[maxn * 10];
node2(){
len = 0;
}
void init(int x){
s[++len] = x;
}
node2 operator + (const node2 &a){
node2 res;
rep(i,1,len) res.s[i] = s[i];
rep(i,1,a.len) res.s[i + len] = a.s[i];
res.len = a.len + len;
return res;
}
void getfail(int m,int a[]){
fail[1] = 0;
int p = 0;
rep(i,2,m){
while ( p && a[p + 1] != a[i] ) p = fail[p];
if ( a[p + 1] == a[i] ) p++;
fail[i] = p;
}
}
bool check(int m,int a[]){
// getfail(m,a);
// int p = 0;
// rep(i,1,len){
// while ( p && s[i] != a[p + 1] ) p = fail[p];
// if ( a[p + 1] == a[i] ) p++;
// if ( p == m ) return 1;
// }
// return 0;
rep(i,1,m) if ( a[i] != s[len - m + i] ) return 0;
return 1;
}
}dt[maxn];
bitset <N> all;
int n,m,ans[maxn],id;
ll k;
int len;
node merge(const node &a,const node &b){
if ( !a.len ) return b;
node res;
res.len = a.len + b.len;
res.pre = a.pre , res.suf = b.suf; //pre和suf中包含了长度1..n-1的所有信息,所以合并的时候直接&就好
res.num = a.num + b.num;
if ( a.len <= len - 2 ) res.pre &= (b.pre >> a.len) | (all << (len - 1 - a.len));
if ( b.len <= len - 2 ) res.suf &= (a.suf << b.len) | (all >> (len - 1 - b.len));
if ( res.len >= len ){
bitset<N> tmp = a.suf & b.pre;
if ( a.len <= len - 2 ) tmp &= all >> (len - 1 - a.len); //如果a的长度不足,则删除高位
if ( b.len <= len - 2 ) tmp &= all << (len - 1 - b.len); //删除低位
res.num += tmp.count();
}
if ( res.num > inf ) res.num = inf;
return res;
}
void init(){
dt[0].init(0) , dt[1].init(1);
rep(i,2,100){
dt[i] = dt[i - 2] + dt[i - 1];
if ( dt[i].len > m ){ id = i; break; }
}
// rep(i,1,dt[id].len) printf("%d",dt[id].s[i]);
// puts("");
}
inline ll calc(int a[]){
all.reset();
rep(i,1,len - 1) all.set(i);
rep(i,0,n) f[i].clear();
f[0].len = 1 , f[1].len = 1;
if ( len == 1 ){
f[0].num = a[1] == 0;
f[1].num = a[1] == 1;
}
else{
rep(i,1,len){
f[0].pre[i - 1] = a[i] == 0;
f[0].suf[i] = a[i] == 0;
f[1].pre[i - 1] = a[i] == 1;
f[1].suf[i] = a[i] == 1;
}
}
rep(i,2,n) f[i] = merge(f[i - 2] ,f[i - 1]);
return f[n].num;
}
void solve(int n,ll k){
if ( n > m ){ len = n - 1; return; }
ans[len = n] = 0;
ll num = calc(ans);
// cout<<num<<endl;
if ( num >= k ){
if ( dt[id].check(n,ans) ) k--;
if ( !k ){ len = n; return; }
solve(n + 1,k);
}
else{
k -= num;
ans[n] = 1;
if ( dt[id].check(n,ans) ) k--;
if ( !k ){ len = n; return; }
solve(n + 1,k);
}
}
int main(){
scanf("%d %lld %d",&n,&k,&m);
init();
solve(1,k);
rep(i,1,len) printf("%d",ans[i]);
puts("");
}