傳送門:https://www.luogu.org/problemnew/show/P5362
題目大意:有一個01串tm,滿足tm(0)=0,tm(i)=tm(i>>1)^(i&1)。給定01串s和整數k,問有多少個本質不同的01串t滿足:t是tm的子串,s是t的前綴,t的長度是|s|+k。
全場無人ac的找規律神題。
關於tm序列,有很多種解釋方式,比如每個數的二進制中1的個數的奇偶性啦,從0開始每次把自身取反接在後面啦等等。對於這個題,最好的解釋方式是這樣的:
從0開始,每次把所有的0變成01,把所有的1變成10。
爲什麼這樣解釋最好呢?因爲我們可以試着把一個tm的子串用這種方式變換回去:
假設一個串s=abcdefg
我們可以把它每2位劃分爲一段,即ab|cd|ef|g或a|bc|de|fg,然後把每一段按上述規則合併爲一個字符。
如果某一段內兩個字符相同,意味着這樣劃分是不合法的。
兩側也許有落單的段,但是根據規則實際上與它們成一段的另一個字符是確定的,我們也可以將其補上。
比如串10100110010,就可以切割爲10|10|01|10|01|0,然後合併成110100。
可以驗證:當串長>3時,合法的切割方案是唯一的。比如串1001,就只能劃分爲10|01,而串1010看似可以劃分爲1|01|0,但是由於這樣縮成的是000因此不合法,所以唯一的劃分方案是10|10。
因此我們就可以通過對切割方案的計數來實現對串的計數。設f(s,k)表示當前串爲s,後面接k個字符的方案數。當|s|+k<=3時特判,否則枚舉2種劃分方案,對於合法的方案進行遞歸操作。用個map對狀態進行記憶化即可。
本質不同的狀態數大約只有O(log|s|+logk)級別,可以通過此題。
ps:關於tm序列的一些其他的性質,可以參見http://oeis.org/A010060和http://www.matrix67.com/blog/archives/5822。
#include<bits/stdc++.h>
using namespace std;
#define gc getchar()
#define pc putchar
#define li long long
int t;
string s;
li k;
#define psi pair<string,li>
#define fi first
#define se second
#define mp make_pair
map<psi,li> mm;
const int mo = 1000000009;
inline li wk(psi p){
if(p.fi.size() == 1){
if(!p.se) return 1;
if(p.se == 1) return 2;
if(p.se == 2) return 3;
}
if(p.fi.size() == 2){
if(!p.se) return 1;
if(p.se == 1) return (p.fi[0] == p.fi[1] ? 1 : 2);
}
if(p.fi.size() == 3 && !p.se) return (p.fi[0] == p.fi[1] && p.fi[1] == p.fi[2] ? 0 : 1);
if(mm.find(p) != mm.end()) return mm[p];
li as = 0;
int i;
bool fg = 1;
string nxt;
nxt.clear();
for(i = 0;i < p.fi.size();i += 2){
if(i == p.fi.size() - 1) nxt += p.fi[i];
else if(p.fi[i] == p.fi[i + 1]){
fg = 0;break;
}
else nxt += p.fi[i];
}
if(fg) as += wk(mp(nxt,(p.fi.size() % 2 ? (p.se >> 1) : (p.se + 1 >> 1))));
fg = 1;nxt.clear();
nxt += (p.fi[0] ^ 1);
for(i = 1;i < p.fi.size();i += 2){
if(i == p.fi.size() - 1) nxt += p.fi[i];
else if(p.fi[i] == p.fi[i + 1]){
fg = 0;break;
}
else nxt += p.fi[i];
}
if(fg) as += wk(mp(nxt,(p.fi.size() % 2 ? (p.se + 1 >> 1) : (p.se >> 1))));
return mm[p] = as;
}
int main(){
cin>>t;
while(t--){
cin>>s>>k;
cout<<wk(mp(s,k)) % mo<<endl;
}
return 0;
}