( ext{Description})
( ext{Solution})
可以看看这道题的前置版本:( ext{POJ - 2778 DNA Sequence}),这样会容易理解一点。
容易发现其实方案数就是所有长度小于等于 (m) 的方案数 (-) 长度小于等于 (m) 的不包含任何关键串的方案数。
考虑第一项其实就是 (26^1+26^2+...+26^n)。
这个可以用等比数列求和或者用矩阵加速来递推。
讲一下矩阵加速。令 (f_n=1+26^1+26^2+...+26^n)。
显然有:
[f_n=f_{n-1} imes 26+1
]
最后求出 (f_n) 再 (-1) 就是第一项。
对于第二项,由于我们需要将矩阵的 ([1,m]) 的状态的第一行之和再相加,可以在矩阵后面添置一维。
比如原矩阵为:
[left[
egin{matrix}
1 & 2 \
3 & 4 \
end{matrix}
ight]
]
我们将最后一列置为 (1),最后一行除了最后一列的那个置为 (0)。
[left[
egin{matrix}
1 & 2 & 1 \
3 & 4 & 1 \
0 & 0 & 1
end{matrix}
ight]
]
你会发现这样无论矩阵怎么乘最后一行是不变的,最后一列除了最后一行的那个数都是上一轮的同行的数相加,比如我们计算上面那个矩阵的平方时,((0,2)) 的答案就是 (1+2+1)。而且保证原矩阵范围未受影响。
注意这样算出来的答案要减去初始赋值的 (1)。
( ext{Code})
#include <cstdio>
#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
#include <queue>
#include <cstring>
using namespace std;
typedef unsigned long long ll;
queue <int> q;
ll ans,sum;
int n,m,t[35][30],f[35],tot;
bool no[35];
char s[10];
struct Matrix {
ll a[35][35]; int n,m;
Matrix() {memset(a,0,sizeof a);}
Matrix operator * (Matrix t) {
Matrix r; r.n=n,r.m=m;
rep(i,0,r.n)
rep(j,0,r.m)
if(a[i][j])
rep(k,0,r.m)
r.a[i][k]=(r.a[i][k]+a[i][j]*t.a[j][k]);
return r;
}
} per;
Matrix qkpow(int y) {
Matrix r; r.n=r.m=per.n;
rep(i,0,r.n) r.a[i][i]=1;
while(y) {
if(y&1) r=r*per;
per=per*per; y>>=1;
}
return r;
}
void Insert() {
int p=0,len=strlen(s+1);
rep(i,1,len) {
int d=s[i]-'a';
if(!t[p][d]) t[p][d]=++tot;
p=t[p][d];
}
no[p]=1;
}
void GetFail() {
rep(i,0,25) if(t[0][i]) q.push(t[0][i]);
while(!q.empty()) {
int u=q.front(); q.pop();
rep(i,0,25)
if(t[u][i]) f[t[u][i]]=t[f[u]][i],q.push(t[u][i]),no[t[u][i]]|=no[f[t[u][i]]];
else t[u][i]=t[f[u]][i];
}
}
void Ori() {
sum=ans=0; tot=0; per=Matrix();
memset(t,0,sizeof t);
memset(no,0,sizeof no);
memset(f,0,sizeof f);
}
void init() {
per=Matrix();
rep(i,0,tot)
if(!no[i])
rep(j,0,25)
if(!no[t[i][j]]) ++per.a[i][t[i][j]];
per.n=per.m=tot+1;
rep(i,0,per.m) per.a[i][per.m]=1;
}
int main() {
while(~scanf("%d %d",&n,&m)) {
Ori();
while(n--) scanf("%s",s+1),Insert();
GetFail(); init();
per=qkpow(m);
rep(i,0,per.m) ans+=per.a[0][i];
per=Matrix(); per.n=per.m=1;
per.a[0][0]=26,per.a[1][0]=per.a[1][1]=1;
per=qkpow(m);
rep(i,0,1) sum+=per.a[i][0];
print(sum-ans,'
'); // sum 与 ans 都多计算了一个 1,所以直接相减就是答案
}
return 0;
}
( ext{Bi Bi Time!})
等比数列求和推出来答案柿子是:
[frac{26^n imes 26-26}{25}
]
然后我跑去求 (25) 在 (2^{64}) 意义下的逆元,求出来这个东西:(15170602326218735249)。
但为什么乘出来不是 (1)?按理来说这两个玩意儿互质不是会有逆元吗?