题解:AT_abc305_g [ABC305G] Banned Substrings
题目:
\(f_{i,a/b,a/b,a/b,a/b,a/b}\):\(i\) 长度的字符串,且最后五个顺次的字符为这些 \(a/b\) 的方案数。
转移可以直接枚举 \(s_i\),发现转移只与后五位有关,直接上个矩乘就完了。
初始化跑暴力 dfs。
从刷表角度构造矩阵即可。自己推
#include<bits/stdc++.h>
using namespace std;
#define ll long long
void xie(int x,int shen=1)
{
if(shen>6) return ;
xie(x/2,shen+1);
putchar('0'+x%2);
if(shen==1) putchar('\n');
}
const int QAQ=130,ovo=33;
const ll mo=998244353;
string s[QAQ];
ll n;
int a[QAQ][8],m,len[QAQ],xian;
int ya[QAQ],no[9][QAQ];
int jie(int xian,int l,int r)
{
xian>>=(l-1);
xian&=((1<<(r-l+1))-1);//
return xian;
}
int bx[QAQ];
void yln()
{
for(int s=0;s<(1<<6);s++)
{
int emm=1;
for(int l=1;l<=6&&emm;l++)
for(int r=l;r<=6&&emm;r++)
if(no[r-l+1][jie(s,l,r)]) emm=0;
if(!emm) bx[s]=1;
// ,xie(s);
}
}
int f[8][QAQ],U;
void dfs(int x,int xian)
{
// cout<<x<<'\n';
int emm=1;
for(int l=1;l<=x-1&&emm;l++)
for(int r=l;r<=x-1&&emm;r++)
if(no[r-l+1][jie(xian,l,r)]) emm=0;
// if(!emm) cout<<"wocao";
f[x-1][xian]+=emm;
if(x>5) return ;
xian<<=1;
xian&=U;
dfs(x+1,xian|1);
dfs(x+1,xian);
}
#define jia(x,y) (x=((x)+(y))%mo)
vector<int> to[ovo];
struct xxx
{
ll jz[ovo][ovo];
void csh()
{
for(int i=0;i<=31;i++)
for(int j=0;j<=31;j++)
jz[i][j]=0;
}
void dw()
{
csh();
for(int i=0;i<=31;i++)
jz[i][i]=1;
}
} zy,nw;
xxx operator *(xxx a,xxx b)
{
xxx c;c.csh();
for(int i=0;i<=31;i++)
for(int j=0;j<=31;j++)
for(int k=0;k<=31;k++)
jia(c.jz[i][j],a.jz[i][k]*b.jz[k][j]);
return c;
}
xxx ksm(xxx x,ll k)
{
xxx da;
da.dw();
for(;k;k/=2,x=x*x) if(k%2==1) da=da*x;
return da;
}
void roxy()
{
zy.csh();
for(int i=0;i<=31;i++)
for(int v:to[i])
zy.jz[i][v]=1;
for(int i=0;i<=31;i++) nw.jz[0][i]=f[5][i];
// ,cout<<f[5][i]<<" ";
}
signed main()
{
// freopen("shuju.in","r",stdin);
// freopen("wode.out","w",stdout);
cin>>n>>m;
for(int i=0;i<5;i++) U|=(1<<i);
for(int i=1;i<=m;i++) cin>>s[i],len[i]=s[i].size();
for(int i=1;i<=m;i++)
{
for(int j=1;j<=len[i];j++)
{
a[i][j]=s[i][j-1]-'a';
ya[i]=(ya[i]<<1);
if(s[i][j-1]=='b') ya[i]|=1;
}
no[len[i]][ya[i]]=1;
}
dfs(1,0);
yln();
for(int s=0;s<32;s++)
{
if(!bx[(s<<1)|1]) to[s].push_back(((s<<1)&U)|1);
if(!bx[s<<1]) to[s].push_back(((s<<1)&U));
}
if(n<=4)
{
int ans=0;
for(int s=0;s<32;s++) jia(ans,f[n][s]);
cout<<ans;
return 0;
}
// for(int i=1;i<=n;i++) cout<<
roxy();
nw=nw*ksm(zy,n-5);
int ans=0;
for(int s=0;s<32;s++) jia(ans,nw.jz[0][s]);
cout<<ans;
return 0;
}