码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2553 禁忌

时间:2018-04-24 13:58:54      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:nbsp   ble   UI   而不是   %s   lse   期望   路径   print   

题意:给定n个禁忌串。由字母表中的前alp的字母组成长度为len的字符串中,定义某个字符串的伤害为存在的一种分割方法使得其中禁忌串的数量的最大值(同一个禁忌串出现两次就算两次)。问期望伤害?

n<=5,禁忌串长度<=15.len<=1e9.

 

标程:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 using namespace std;
 5 typedef long double ld;
 6 const int N=80;
 7 int n,len,alp,ed,tag[N],son[N][26],sc,fail[N];
 8 ld p; queue<int> q; char s[N];
 9 struct node{ld g[N][N];}A;
10 node operator * (node A,node B)
11 {
12     node c;
13     for (int i=0;i<=ed;i++)//注意端点是从0到ed!
14       for (int j=0;j<=ed;j++)
15       {
16           c.g[i][j]=0;  
17         for (int k=0;k<=ed;k++)
18           c.g[i][j]+=A.g[i][k]*B.g[k][j];
19       }
20     return c;
21 }
22 node ksm(node x,int y)
23 {
24    node res=x;y--;//技巧,避免繁冗的初始化 
25    while (y){if (y&1) res=res*x; x=x*x; y>>=1;}
26    return res;
27 }
28 void ins(char *s)
29 {
30     int now=0,sl=strlen(s);
31     for (int i=0,c;i<sl;now=son[now][c],i++)
32        if (!son[now][c=s[i]-a]) son[now][c]=++sc;
33     tag[now]=1;
34 }
35 void build()
36 {
37     for (int i=0;i<alp;i++) if (son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
38     while (!q.empty())
39     {
40         int now=q.front();q.pop();
41         for (int i=0,y;i<alp;i++)
42           if (y=son[now][i]) q.push(y),
43             fail[y]=son[fail[now]][i],tag[y]|=tag[fail[y]];
44           else son[now][i]=son[fail[now]][i];
45     }
46 }
47 int main()
48 {
49     scanf("%d%d%d",&n,&len,&alp);
50     for (int i=1;i<=n;i++) scanf("%s",s),ins(s);
51     build();ed=sc+1;p=1.0/alp;
52     for (int i=0;i<=sc;i++)
53       for (int j=0;j<alp;j++)
54         if (tag[son[i][j]]) A.g[i][0]+=p,A.g[i][ed]+=p;else A.g[i][son[i][j]]+=p;
55     A.g[ed][ed]=1;
56     printf("%.10lf\n",(double)ksm(A,len).g[0][ed]);
57     return 0;
58 }

 

易错点:1.注意AC自动机的节点数为sc,而不是n。矩阵转移的循环范围要注意。

2.技巧:矩阵快速幂的时候可以先把res设为x,进行y-1次的幂操作,避免单位矩阵初始化。

 

题解:AC自动机+矩阵快速幂优化dp

沿用梁大大的思路:15*5的串规模肯定是AC自动机。步长1e9就别想着枚举了,矩阵快速幂优化dp。

这道题是分割方案,贪心来看,就是每次匹配到一个串,就返回起点重新来。这样就避免了串统计重叠。

将所有禁忌串扔进AC自动机,并在禁忌节点打上标记(别往状压方向去想)。

处理出A矩阵,A[i][j]表示从AC自动机上的i节点到j节点可以一步走到,权值设置成1/alp。如果下一个转移到禁忌串了,就跳到根,否则就往儿子走。为了方便统计答案,我们另设一个用来统计的终止节点T。跳到根的时候同时也跳往T。注意T到T的概率(权值)设为1。就是待在原地不再转移。A^len的[0][T]即是答案。

看上去特别喵~对于一个串,它的伤害最大为k的分割方案中,每一个串都会在T终止一次,所以会被统计入k条权值为(1/alp)^len的路径,恰是这个串的伤害期望。

bzoj2553 禁忌

标签:nbsp   ble   UI   而不是   %s   lse   期望   路径   print   

原文地址:https://www.cnblogs.com/Scx117/p/8921684.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!