tyvj P1519 博彩游戏(AC自动机+DP滚动数组)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tyvj P1519 博彩游戏(AC自动机+DP滚动数组)相关的知识,希望对你有一定的参考价值。
P1519 博彩游戏
背景
Bob最近迷上了一个博彩游戏……
描述
这个游戏的规则是这样的:
每花一块钱可以得到一个随机数R,花上N块钱就可以得到一个随机序列;
有M个序列,如果某个序列是产生的随机序列的子串,那么就中奖了,否则不中。
Bob会告诉你这M个序列,和身上有的钱的总数N,当然还有R的范围。
请你告诉Bob中奖的概率有多少?
每花一块钱可以得到一个随机数R,花上N块钱就可以得到一个随机序列;
有M个序列,如果某个序列是产生的随机序列的子串,那么就中奖了,否则不中。
Bob会告诉你这M个序列,和身上有的钱的总数N,当然还有R的范围。
请你告诉Bob中奖的概率有多少?
输入格式
第一行三个用空格隔开的数N、M和R的范围R。
其中1<=R<=9,0<N<=60,0<M<=20000。
下面M行每行一个字符串(长度小于等于20),字符串的每一位范围在1-r之间
保证必要运算都在64位整型范围内。
其中1<=R<=9,0<N<=60,0<M<=20000。
下面M行每行一个字符串(长度小于等于20),字符串的每一位范围在1-r之间
保证必要运算都在64位整型范围内。
输出格式
一行一个实数,表示中奖的概率(保留小数点后5位小数)。
测试样例1
输入
5 1 3
1
输出
0.86831
备注
数据分布:
第1个点~第10个点,每个点5分;
第11个点~第15个点,每个点10分。
对于样例的解释:
随机序列一共有3^5=243个,其中包含"1"的个数为211个,则概率为211/243=0.86831Bob HAN
第1个点~第10个点,每个点5分;
第11个点~第15个点,每个点10分。
对于样例的解释:
随机序列一共有3^5=243个,其中包含"1"的个数为211个,则概率为211/243=0.86831Bob HAN
【思路】
AC自动机+DP。
与bzoj1030一样思路都是要转化为求AC自动机上不经过单词节点的方案。不同的是这个题需要用滚动数组不然MLE <_<
尼玛tyvj上double要用%f,让我WA了千万发,我说以前怎么提交不过WTF
【代码】
1 #include<set> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<iostream> 6 using namespace std; 7 typedef long long LL; 8 const int N=20000+5,L=20+5; 9 const int node = N*L; 10 const int sigma = 10; 11 12 char s[L]; int n,m,r; LL d[2][node]; 13 14 struct ACauto{ 15 int ch[node][sigma],f[node],val[node],sz; 16 void clear() { 17 sz=1; memset(ch[0],0,sizeof(ch[0])); 18 } 19 void insert(char *s) { 20 int n=strlen(s),u=0; 21 for(int i=0;i<n;i++) { 22 int c=s[i]-‘1‘; 23 if(!ch[u][c]) { 24 memset(ch[sz],0,sizeof(ch[sz])); 25 val[sz]=0; ch[u][c]=sz++; 26 } 27 u=ch[u][c]; 28 } 29 val[u]=1; 30 } 31 void get_Fail() { 32 queue<int> q; 33 f[0]=0; 34 for(int c=0;c<r;c++) 35 if(ch[0][c]) f[ch[0][c]]=0,q.push(ch[0][c]); 36 while(!q.empty()) { 37 int qr=q.front(); q.pop(); 38 for(int c=0;c<r;c++) { 39 int u=ch[qr][c]; if(!u) continue; 40 q.push(u); int v=f[qr]; 41 while(v&&!ch[v][c]) v=f[v]; 42 if(val[ch[v][c]]) val[u]=1; 43 f[u]=ch[v][c]; 44 } 45 } 46 } 47 }ac; 48 int que[2][N],cnt[2]; 49 int main() { 50 //freopen("in.in","r",stdin); 51 //freopen("out.out","w",stdout); 52 scanf("%d%d%d",&m,&n,&r); 53 ac.clear(); 54 for(int i=0;i<n;i++) { 55 scanf("%s",s); ac.insert(s); 56 } 57 ac.get_Fail(); 58 d[0][0]=1; 59 int x=0; 60 for(int i=1;i<=m;i++) { 61 x^=1; 62 memset(d[x],0,sizeof(d[x])); 63 for(int j=0;j<ac.sz;j++) if(!ac.val[j]&&d[x^1][j]) { 64 for(int c=0;c<r;c++) { 65 int k=j; while(!ac.ch[k][c]&&k) k=ac.f[k]; 66 d[x][ac.ch[k][c]]=d[x^1][j]+d[x][ac.ch[k][c]]; 67 } 68 } 69 } 70 LL ans1=0,ans2=1; 71 for(int i=1;i<=m;i++) ans2*=(LL)r; 72 for(int i=0;i<ac.sz;i++) 73 if(!ac.val[i]) ans1+=d[x][i]; 74 double f=((double)ans2-(double)ans1)/(double)ans2; 75 printf("%.5f\n",f); 76 return 0; 77 }
以上是关于tyvj P1519 博彩游戏(AC自动机+DP滚动数组)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1444[Jsoi2009]有趣的游戏 AC自动机+概率DP+矩阵乘法
BZOJ4820[Sdoi2017]硬币游戏 AC自动机+概率DP+高斯消元