ZR24NOIP1B. 数数
ZR24NOIP1B. 数数
给你一个长度为 \(n\le 1600\) 的二进制数,其中某些位未知,是 ?
。问 ?
的所有取值得到的 \(x\),\([0,x-1]\) 中不含长度为 \(k\le 20\) 的回文串的数字(含前导 \(0\))的个数的和。
首先显然是数位 DP。
考虑从高位枚举到低位,假设没有 ?
,状态记位数 \((1600)\) 和是否顶到上界 \((0/1)\)。枚举第 \(i\) 位填什么数字,需要判断填上之后会不会和前面 \(k-1\) 位形成一个回文串,因此我们还要记录前 \(k-1\) 位是什么 \((2^{19})\)。有问号的话转移的时候再枚举一下 ?
填什么就好了。然后判断回文串,但是显然这样过不了。我们直接预处理所有可能的回文串 \((2^{10})\),然后把他们丢到 AC 自动机里,状态改记 AC 自动机节点编号,转移的时候跳一下指针。容易发现因为回文串左右两边是一样的,所以回文串个数只有 \(2^{10}\)。
复杂度:AC 自动机预处理时间和空间都是 \(2^{\frac{k}{2}}k\),DP 转移状态是 \(n2^{\frac{k}{2}}k\) 的,可以通过。
#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x++)
using namespace std;
typedef long long ll;
const int N=2e3,mod=1e9+7;
struct acam{
int son[N*21][2],sum[N*21];
int fail[N*21]={0,1};
int cnt=1;
void insert(int x,int len) {
int p=1;
rep(i,0,len-1) {
int op=x&1;
if(!son[p][op]) son[p][op]=++cnt;
p=son[p][op];
x>>=1;
}
sum[p]++;
}
void build(){
queue<int> q;
rep(i,0,1) {
if(son[1][i]) q.push(son[1][i]),fail[son[1][i]]=1;
else son[1][i]=1;
}
while(!q.empty()) {
int u=q.front();
q.pop();
rep(i,0,1) {
int v=son[u][i];
if(v) fail[v]=son[fail[u]][i],q.push(v);
else son[u][i]=son[fail[u]][i];
}
}
}
}T;
int n,k;
char s[N];
ll dp[2][N*21][2];
int re(int x){
if(k&1) x>>=1;
int y=0;
rep(i,1,k/2){
y<<=1;
y+=x&1;
x>>=1;
}
return y;
}
void add(ll &a,ll b) {a=a+b>=mod?a+b-mod:a+b;}
void solve(int i,int x) {
rep(l1,0,1)
rep(p,1,T.cnt) {
if(dp[i^1][p][l1]==0) continue;
rep(a,0,1) {
if(a>x&&l1) continue;
int l=l1&a==x;
int ps=T.son[p][a];
if(T.sum[ps]) continue;
add(dp[i][ps][l],dp[i^1][p][l1]);
}
}
}
ll ans;
int main(){
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
sf("%d%d",&n,&k);
sf("%s",s+1);
rep(i,0,(1<<((k+1)/2))-1) {
int x=(i<<(k/2))+re(i);
// pf("%d ",x);
T.insert(x,k);
}
pf("\n");
T.build();
dp[0][1][1]=1;
rep(i,1,n) {
memset(dp[i&1],0,sizeof(dp[i&1]));
if(s[i]=='0') solve(i&1,0);
else if(s[i]=='1') solve(i&1,1);
else solve(i&1,0),solve(i&1,1);
}
rep(i,1,T.cnt){
add(ans,dp[n&1][i][0]);
}
pf("%lld\n",ans);
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18415308