题意:
分析:
不会分析 , 直接找规律:
肉眼分析可以发现, (T.M) 序列的生成方式有两种:
- 取反然后复制一遍 (0110 o 01101001)
- ( iny color{white}{ ext{不}})容易发现 (0110 o 0(1)1(0)1(0)0(1))
但是第一个性质不方便用,因为 (|S|+k) 不一定是 (2) 的整数次幂,所以我们考虑第二种方法
我们发现在后面添加的 (k) 的布尔序列也会是 (01) ,(10) 交替的,所以一定不会存在连续的三个以上的相同字符,所以我们可以反向推导,由第二个性质可以知道 (0 o 01) (1 o 10) 所以我们每一次可以将 (S) 长度减半 (k) 也减半,这样递归 (log k) 层就能得到 (k<=2) 的情况,然后我们手动判掉 (n,k<=3) 的情况,顺便对 (S,k) 哈希一下之后记忆化
具体来说就是,每次分两种情况讨论,一种是第一位空出来与前面的拼成一个 (0),第二种就是从第一位开始两个一组
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define psl pair<string,long long>
using namespace std;
namespace zzc
{
typedef long long ll;
const ll mod = 1e9+9;
map<psl,ll> f;
long long solve(string s,long long k)
{
if(f[mk(s,k)]) return f[mk(s,k)];
long long n=s.size(),res=0;
if(n==1&&k<=2) return k+1;
if(n==2&&k==0) return 1;
if(n==2&&k==1) return (s[0]==s[1])?1:2;
if(n==3&&k==0) return (s[0]!=s[1]||s[1]!=s[2]);
bool flag=true;
string nxt;
for(int i=0;i<n;i+=2)
{
if(i==n-1||s[i]!=s[i+1]) nxt+=s[i];
else {flag=false;break;}
}
if(flag) res+=solve(nxt,(n&1)?(k>>1):((k+1)>>1))%mod;
nxt=((s[0]-'0')^1)+'0';
flag=true;
for(int i=1;i<n;i+=2)
{
if(i==n-1||s[i]!=s[i+1]) nxt+=s[i];
else {flag=false;break;}
}
if(flag) res+=solve(nxt,(n&1)?((k+1)>>1):(k>>1))%mod;
return f[mk(s,k)]=res%mod;
}
void work()
{
ios::sync_with_stdio(false);
string s;
ll k,t;
cin>>t;
while(t--)
{
cin>>s>>k;
cout<<solve(s,k)%mod<<'
';
}
}
}
int main()
{
zzc::work();
return 0;
}