Microgene
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 382 Accepted Submission(s): 223
To simplify the problem, a DNA or a Microgene is considerd as a string consisting of character 'A', 'T', 'C' and 'G'. And a Microgene is in the DNA if the Microgene string is the substring of the DNA string. All Microgenes given are different and with the same hereditary effect.
We have carefully selected several similar problems for you: 3961 3969 3963 3964 3965
题解:
太强了,真是太强了,我到现在还是不懂这道题的矩阵快速幂在干什么。
直接复制网上的题解吧。。。
题目大意:给定m个DNA病毒序列,求碱基构成的长度为n且含有两个以上DNA病毒序列,结果对10007取模。
解题思路:本题代码量大,较为综合,需用到AC自动机改造而成的Trie图、DP思想、矩阵快速幂。
如果n比较小,那么本题可以用DP解,由于题目明显的有三个状态,未含病毒串、含一个病毒串,含两个及两个以上病毒,根据这三个就可以写出一个状态转移方程。但是本题可以简化一下,先求出总的组合种数,再减去含有一个病毒串和未含病毒串的种数就是解了。那么状态就只有2个。
状态转移方程为:if (j->next 为病毒串) dp[i+1][j->next][1] += dp[i][j][0] ;
else if (j->next非病毒串) dp[i+1][j->next][1] += dp[i][j][1];
dp[i+1][j->next][0] += dp[i][j][0];
但是本题n特别大,必须用矩阵进行优化。先将Trie图转化为一个(total * 2) * (total * 2)(total为总节点数)可达矩阵,如果i < total,那说明这个节点和他的后缀不含有病毒串,如果i > total,那说明这个节点和他的后缀含有1个病毒串。
具体实现是这样的,if (i->next->flag) matrix[i][i->next+total]++;
else matrix[i][i->next]++,matrix[i+total][i->next+total]++;
这样,矩阵就被分成四块相当于四个象限,第2个象限(i和j都小于total)怎么走都不会出现病毒串,那么经过A^n,他们的值就是最后病毒序列为0个的种数。第1个象限表示i走到j-total会出现一个病毒DNA序列,第四个象限i-total走到j-total,原来含1个病毒串现在还是1个。
代码(这个比较浅显易懂):
const mo=10007;
type node=record danger:boolean;
fail:longint;
son:array[1..4]of longint;
end;
arr=array[0..100,0..100]of longint;
var
b,bb,c:arr;
q:array[0..100]of longint;
a:array[0..100]of node;
s:string;
i,j,tot,n,m,ans,sum:longint;
function number(ch:char):longint;
begin
case ch of
'A':number:=1;
'T':number:=2;
'C':number:=3;
'G':number:=4;
end;
end;
procedure add;
var
i,t,len,u:longint;
begin
len:=length(s);
t:=1;
for i:=1 to len do
begin
u:=number(s[i]);
if a[t].son[u]=0 then
begin
inc(tot);
fillchar(a[tot],sizeof(node),0);
a[t].son[u]:=tot;
end;
t:=a[t].son[u];
end;
a[t].danger:=true;
end;
procedure setac;
var
p,l,r,u:longint;
begin
l:=0;r:=1;q[1]:=1;
while l<r do
begin
inc(l);
u:=q[l];
a[u].danger:=a[u].danger or a[a[u].fail].danger;
for i:=1 to 4 do
begin
if a[u].son[i]<>0 then
begin
inc(r);
q[r]:=a[u].son[i];
end;
p:=a[u].fail;
while(p>0)and(a[p].son[i]=0)do p:=a[p].fail;
if p=0 then a[a[u].son[i]].fail:=1
else a[a[u].son[i]].fail:=a[p].son[i];
end;
end;
end;
procedure cheng(var a,b:arr);
var
i,j,k:longint;
begin
fillchar(c,sizeof(c),0);
for i:=1 to 2*tot do
for j:=1 to 2*tot do
for k:=1 to 2*tot do
c[i,j]:=(c[i,j]+(a[i,k]*b[k,j])mod mo)mod mo;
a:=c;
end;
procedure quick(k:longint);
begin
if k=1 then exit;
quick(k shr 1);
cheng(b,b);
if k and 1=1 then
cheng(b,bb);
end;
procedure quick1(k:longint);
begin
if k=1 then exit;
quick1(k shr 1);
sum:=(sum*sum)mod mo;
if k and 1=1 then
sum:=(sum*4)mod mo;
end;
procedure make_matrix;
var
p,u:longint;
begin
fillchar(b,sizeof(b),0);
for i:=1 to tot do
begin
for j:=1 to 4 do
begin
p:=i;
while (p>0)and(a[p].son[j]=0)do p:=a[p].fail;
if p=0 then
begin
if not a[i].danger then
begin
inc(b[tot+i,1+tot]);
inc(b[i,1]);
end
else inc(b[i,tot+1]);
end
else
begin
u:=a[p].son[j];
if not a[i].danger then
begin
inc(b[tot+i,u+tot]);
inc(b[i,u]);
end
else inc(b[i,u+tot]);
end;
end;
end;
{for i:=1 to 2*tot do
begin
for j:=1 to 2*tot do
write(b[i,j],' ');
writeln;
end;}
bb:=b;
quick(m);
{for i:=1 to 2*tot do
begin
for j:=1 to 2*tot do
write(b[i,j],' ');
writeln;
end;}
sum:=4;
quick1(m);
ans:=0;
for i:=1 to tot do
ans:=(ans+b[1,i])mod mo;
for i:=tot+1 to 2*tot do
if not a[i-tot].danger then
ans:=(ans+b[1,i])mod mo;
writeln(((sum-ans)mod mo+mo)mod mo);
end;
begin
while not seekeof do
begin
readln(n,m);
tot:=1;
fillchar(a[1],sizeof(node),0);
for i:=1 to n do
begin
readln(s);
add;
end;
setac;
make_matrix;
end;
end.