题解:SP1676 GEN - Text Generator
CuteGielHina · · 题解
:::info[提示] 本文使用了 Deepseek 进行了润色,严格保证人类贡献大于 AI 贡献。 :::
MX 题单里做到的。
前置芝士:AC 自动机,矩阵快速幂。
Problem.
给定
Solution.
一眼 dp。
直接算“包含”显然不好算,正难则反,不妨从反向入手。
显然的,答案 = 所有可能的字符串总数 - 不包含任何给定模式串的字符串的数量。
注意到总字符串的数量为
因此,我们可以计算出长度为
构建 AC 自动机,把所有模式串插入 Trie 树并构建 fail 指针。
先讲如何处理非法状态。
显然有以下两种情况不合法:
-
本身是某个模式串结尾的节点
-
所有通过 fail 指针能指向一个模式串结尾的节点。因为这意味着当前匹配的字符串包含了某个模式串作为后缀,这也是不合法的。
将它们标记出来,后面方便处理。
然后考虑怎么 dp。
定义
初始化显然
定义
考虑如何状态转移。
设当前在节点
枚举下一个节点
如果
否则就继续走下去。
则状态转移方程为
形式化一点:
其中
注意到
矩阵快速幂的实现就简单点。
定义状态向量
构造转移矩阵
则
用矩阵快速幂计算
然后这题就做完了。
时间复杂度
贴个代码。
:::info[代码]
#include<bits/stdc++.h>
#define BUF 1<<20
#define IL inline
#define ll long long
#define ri register int
#define F(i,a,b) for(ri i=a;i<=b;i++)
#define FF(i,a,b) for(ri i=b;i>=a;i--)
#define u64 uint64_t
#define ull unsigned long long
#define i128 __int128
#define vec vector
#define vi vector<int>
#define vll vector<ll>
#define vb vector<bool>
#define prq priority_queue
#define pii pair<int,int>
#define pill pair<int,ll>
#define plli pair<ll,int>
#define um unordered_map
#define mii map<int,int>
#define us unordered_set
#define pb(x) push_back(x)
#define fi first
#define se second
#define fr() front()
#define bk() back()
#define beg() begin()
#define Fill(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=105,mod=1e4+7;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-9;
char buf[BUF],*p1=buf,*p2=buf;
#define getchar_unlocked()((p1==p2)&&(p2=(p1=buf)+fread(buf,1,BUF,stdin),p1==p2)?EOF:*p1++)
int n,l,tot,ans,bad;
string s;
struct Matrix{
int a[N][N],n;
Matrix(int n=0,bool id=0):n(n){
Fill(a,0);
if(id){
F(i,0,n-1) a[i][i]=1;
}
}
Matrix operator *(const Matrix&oth)const{
Matrix res(n);
F(i,0,n-1){
F(k,0,n-1){
if(!a[i][k]) continue;
F(j,0,n-1){
res.a[i][j]=(res.a[i][j]+a[i][k]*oth.a[k][j])%mod;
}
}
}
return res;
}
};
IL Matrix qpow1(Matrix b,int e){
Matrix res(b.n,1);
while(e){
if(e&1) res=res*b;
b=b*b;
e>>=1;
}
return res;
}
struct ACAM{
int tr[N][26],fail[N],idx;
bool dan[N];
IL void init(){
Fill(tr,0),Fill(fail,0),Fill(dan,0),idx=0;
}
IL void insert(string s){
int p=0;
for(char ch:s){
int c=ch-'A';
if(!tr[p][c]) tr[p][c]=++idx;
p=tr[p][c];
}
dan[p]=1;
}
IL void build(){
queue<int> q;
F(i,0,25){
if(tr[0][i]){
q.push(tr[0][i]);
}
}
while(!q.empty()){
int u=q.fr(); q.pop();
dan[u]|=dan[fail[u]];
F(i,0,25){
if(tr[u][i]){
fail[tr[u][i]]=tr[fail[u]][i];
q.push(tr[u][i]);
}
else tr[u][i]=tr[fail[u]][i];
}
}
}
IL Matrix buildM(){
Matrix mat(idx+1);
F(u,0,idx){
if(dan[u]) continue;
F(i,0,25){
if(!dan[tr[u][i]]) mat.a[u][tr[u][i]]++;
}
}
return mat;
}
} acam;
IL int qpow2(int e){
int a=26,res=1;
while(e){
if(e&1) res=res*a%mod;
a=a*a%mod;
e>>=1;
}
return res;
}
IL int read(){
int k=0,f=1;
char c=getchar_unlocked();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar_unlocked();
}
while(c>='0'&&c<='9') k=k*10+c-'0',c=getchar_unlocked();
return k*f;
}
IL void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else write(x/10),putchar(x%10+'0');
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
while(cin>>n>>l) {
bad=0;
acam.init();
F(i,1,n){
cin>>s;
acam.insert(s);
}
acam.build();
Matrix t=acam.buildM();
Matrix fi=qpow1(t,l);
F(i,0,acam.idx){
bad=(bad+fi.a[0][i])%mod;
}
tot=qpow2(l);
ans=(tot-bad+mod)%mod;
write(ans);
putchar('\n');
}
return 0;
}
:::
这题有个弱化版 P4052,但是那题