概率、期望
BZOJ1076 奖励关
你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。
在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃)。
宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立。
获取第i种宝物将得到Pi分,但并不是每种宝物都是可以随意获取的。
第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过一次,才能吃第i种宝物(如果系统抛出了一个目前不能吃的宝物,相当于白白的损失了一次机会)。
注意,Pi可以是负数,但如果它是很多高分宝物的前提,损失短期利益而吃掉这个负分宝物将获得更大的长期利益。
假设你采取最优策略,平均情况你一共能在奖励关得到多少分值?
1<=k<=100,1<=n<=15
正着做感觉不是很方便,所以考虑倒着做。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=100+7,maxs=(1<<15)+7; int n,k,d[maxn]; db v[maxn],dp[maxn][maxs]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { read(k); read(n); int x; For(i,1,n) { read(v[i]); read(x); while(x) { d[i]|=(1<<x-1); read(x); } } int sz=1<<n; Rep(i,k,1) { For(j,0,sz-1) { For(t,1,n) if((j&d[t])==d[t]) dp[i][j]+=max(dp[i+1][j],dp[i+1][j|(1<<t-1)]+v[t]); else dp[i][j]+=dp[i+1][j]; dp[i][j]/=n; } } printf("%.6f\n",dp[1][0]); return 0; }
Uva 11201麻球繁衍
你有一坨K个毛球。这种毛球只会存活一天。
在死亡之前,一个毛球有P_i的概率生出i个毛球(i=0,1,…,n-1)。
m天后所有毛球都死亡的概率是多少?(包含在第m天前全部死亡的情况)
1<=n<=1000,0<=k<=1000,0<=m<=1000
dp[i]表示最初有一个毛球,最后再第i天没有毛球的概率。
计算dp[i+1]我们枚举第一天毛球的的繁衍量,如果是j,那么再过i天没有毛球的概率就是$dp[i]^j$
bzoj3450 Easy
某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(
我们来简化一下这个游戏的规则
有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a个comb就有a*a分,comb就是极大的连续o。
比如ooxxxxooooxxx,分数就是2*2+4*4=4+16=20。
Sevenkplus闲的慌就看他打了一盘,有些地方跟运气无关要么是o要么是x,有些地方o或者x各有50%的可能性,用?号来表示。
比如oo?xx就是一个可能的输入。
那么WJMZBMR这场osu的期望得分是多少呢?
n<=300000
因为平方一类的不是一次的概率不是很好算,但是我们知道,假如原来有连续的i-1个,现在再多一个,多出来的代价就是$i^2 -(i-1)^2 = 2 \times i -1$
这个是一次的,所以我们先求出每个点连续o的个数的期望。剩下的就很好算了
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=3e5+7; int n; char s[maxn]; db ans[maxn],d[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { read(n); scanf("%s",s+1); For(i,1,n) { if(s[i]=='x') d[i]=0,ans[i]=ans[i-1]; else if(s[i]=='o') d[i]=d[i-1]+1,ans[i]=ans[i-1]+2*d[i]-1; else { ans[i]=ans[i-1]+d[i-1]+0.5; d[i]=(d[i-1]+1)/2; } } printf("%.4f",ans[n]); return 0; }
bzoj1426 收集邮票
有n种不同的邮票,皮皮想收集所有种类的邮票。
唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n。
但是由于凡凡也很喜欢邮票,所以皮皮购买第k张邮票需要支付k元钱。
现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。
N<=10000
这竟然是第一个我可以自己做出来的概率期望题。虽然也很无脑。
令$f[i]$表示还剩i种邮票没有收集到,期望还需要买几张邮票
$f[i]= \frac{n-i}{n} \times f[i] + \frac{i}{n} \times f[i-1] +1$
解得$f[i]=f[i-1]+n/i$
令$dp[i]$表示有i种邮票没收集到,期望需要多少钱买邮票
$dp[i]= \frac{n-i}{n} \times (dp[i]+f[i]+1) + \frac{i}{n} \times (dp[i-1]+f[i-1]+1)$
解得$dp[i]=dp[i-1]+f[i-1]+ \frac{n-i}{i} \times f[i] +1 $
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=1e4+7; int n; db f[maxn],dp[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { read(n); For(i,1,n) f[i]=f[i-1]+(db)n/i; For(i,1,n) dp[i]=dp[i-1]+f[i-1]+(db)f[i]*(n-i)/i+(db)n/i; printf("%.2f\n",dp[n]); return 0; }
bzoj3270 博物馆
Petya和他的朋友Vasya决定去参观一座城堡博物馆。
这座博物馆包含由m条走廊连接的n间房间,并且满足可以从任何一间房间到任何一间别的房间。
两个人在博物馆里逛了一会儿后两人决定分头行动,去看各自感兴趣的艺术品。他们约定在下午六点到一间房间会合。然而他们忘记了一件重要的事:他们并没有选好在哪儿碰面。
等时间到六点,他们开始在博物馆里到处乱跑来找到对方(他们没法给对方打电话因为电话漫游费是很贵的)
他们每个人采取如下的行动方法:每一分钟做决定往哪里走,有Pi 的概率在这分钟内不去其他地方(即呆在房间不动),
有1-Pi 的概率他会在相邻的房间中等可能的选择一间并沿着走廊过去。这里的i指的是当期所在房间的序号。在古代建造是一件花费非常大的事,因此每条走廊会连接两个不同的房间,并且任意两个房间至多被一条走廊连接。
两个男孩同时行动。当两个人在某个时刻选择前往同一间房间,那么他们就会在那个房间相遇。
两个男孩现在分别处在a,b两个房间,求两人在每间房间相遇的概率。
n<=20
因为概率之间相互依赖形成环,所以需要高斯消元解方程,O(n^6)
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=400+7,maxm=maxn*maxn; int n,m,S,T;db p[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } const db eps=1e-12,PI=acos(-1); int get_id(int x,int y) {return (x-1)*n+y;} int dcmp(db x){return fabs(x)<eps? 0:(x>0? 1:-1);} int fir[maxn],nxt[2*maxm],to[2*maxm],e=0,ind[maxn]; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; to[++e]=x;nxt[e]=fir[y];fir[y]=e; ++ind[x]; ++ind[y]; } db D[maxn][maxn]; void Gauss() { int nn=n*n,pos=0; For(i,1,nn) { For(j,i,nn) if(dcmp(D[j][i])!=0) {pos=j; break;} if(i!=pos) swap(D[i],D[pos]); Rep(j,nn+1,i) D[i][j]/=D[i][i]; For(j,i+1,nn) Rep(k,nn+1,i) D[j][k]-=D[j][i]*D[i][k]; } Rep(i,nn,1) For(j,i+1,nn) if(dcmp(D[i][j])!=0) { D[i][n*n+1]-=D[i][j]*D[j][n*n+1]; } } int main() { read(n); read(m); read(S); read(T); int x,y; For(i,1,m) { read(x); read(y); add(x,y); } For(i,1,n) scanf("%lf",&p[i]); int id;db P; For(i,1,n) For(j,1,n) if(i!=j) { id=get_id(i,j); D[id][id]=1-p[i]*p[j]; for(x=fir[i];x;x=nxt[x]) D[get_id(to[x],j)][id]-=p[j]*(1-p[i])/ind[i]; for(y=fir[j];y;y=nxt[y]) D[get_id(i,to[y])][id]-=p[i]*(1-p[j])/ind[j]; P=(1-p[i])*(1-p[j])/ind[i]/ind[j]; for(x=fir[i];x;x=nxt[x]) for(y=fir[j];y;y=nxt[y]) D[get_id(to[x],to[y])][id]-=P; } else { id=get_id(i,i); D[id][id]=1; } D[get_id(S,T)][n*n+1]=1; Gauss(); For(i,1,n) printf("%.6f ",D[get_id(i,i)][n*n+1]); return 0; }
bzoj4872 分手是祝愿
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=1e5+7; const ll mod=100003; ll n,k,a[maxn],f[maxn],last,tot,g[maxn],inv[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { read(n); read(k); For(i,1,n) read(a[i]); Rep(i,n,1) { for(int j=i;j<=n;j+=i) if(f[j]) a[i]^=1; if(a[i]) { ++tot; f[i]=1; } } if(tot<=k) { For(i,2,n) tot=tot*i%mod; printf("%lld",tot); } else { g[n]=inv[1]=1; For(i,2,n) inv[i]=(mod-mod/i)*inv[mod%i]%mod; Rep(i,n-1,k+1) g[i]=((n-i)*g[i+1]+n)%mod*inv[i]%mod; ll ans=0; For(i,k+1,tot) ans+=g[i]; ans+=k; ans%=mod; For(i,2,n) ans=ans*i%mod; printf("%lld",ans); } return 0; }
bzoj5197
1.若一张牌发动了技能,那么将结束此回合。
2.若一张牌发动过技能那么它不能再发动技能。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=220+7; int Td,n,m; db f[maxn][maxn],g[maxn],p[maxn][maxn],d[maxn],ans; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } const db eps=1e-15; int dcmp(db x) {return fabs(x)<eps? 0:(x>0? 1:-1);} int main() { read(Td); while(Td--) { memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); read(n); read(m); ans=0; For(i,1,n) { scanf("%lf%lf",&p[i][1],&d[i]); p[i][1]=1-p[i][1]; p[i][0]=1; For(j,2,m) p[i][j]=p[i][j-1]*p[i][1]; } For(i,0,m) p[0][i]=1; f[0][m]=1; For(i,0,n-1) For(j,0,m) if(dcmp(f[i][j])) { //not choose f[i+1][j]+=f[i][j]*p[i][j]; //choose one if(j) f[i+1][j-1]+=f[i][j]*(1-p[i][j]); } For(i,1,n) { For(j,1,m) g[i]+=f[i][j]*(1-p[i][j]); ans+=g[i]*d[i]; } printf("%.10f\n",ans); } return 0; }
bzoj2438杀人游戏
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=3e5+7,maxm=1e6+7; int n,m,ans,p[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxm],to[maxm],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; } int FIR[maxn],NXT[maxm],TO[maxm],E=0,ind[maxn]; void ADD(int x,int y) { TO[++E]=y;NXT[E]=FIR[x];FIR[x]=E; ++ind[y]; } int dfn[maxn],low[maxn],dfn_clock; int size[maxn],bel[maxn],toth,zz[maxn],t; bool inz[maxn]; void tj(int pos) { dfn[pos]=low[pos]=++dfn_clock; zz[++t]=pos; inz[pos]=1; int y,z; for(y=fir[pos];y;y=nxt[y]) { if(dfn[z=to[y]]) { if(inz[z]) low[pos]=min(low[pos],dfn[z]); continue; } tj(z); low[pos]=min(low[pos],low[z]); } if(low[pos]==dfn[pos]) { ++toth; do { bel[zz[t]]=toth; inz[zz[t]]=0; size[toth]++; }while(zz[t--]!=pos); } } void tp() { int s=0,t=0,x,y,z; For(i,1,toth) if(!ind[i]) zz[++t]=i; ans=t; For(i,1,t) if(size[x=zz[i]]==1) { for(y=FIR[x];y;y=NXT[y]) { if(ind[z=TO[y]]<2) { s=i; break; } } if(s!=i) {ans--;return;} } } int main() { read(n); read(m); int x,y,z; For(i,1,m) { read(x); read(y); add(x,y); } For(i,1,n) if(!dfn[i]) tj(i); For(i,1,n) { for(y=fir[i];y;y=nxt[y]) { if(bel[z=to[y]]==bel[i]||p[bel[z]]==i) continue; ADD(bel[i],bel[z]); p[bel[z]]=i; } } tp(); printf("%.6f\n",(db)(n-ans)/(db)n); return 0; }
bzoj1419 Red is good
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) const int maxn=5000+7; int n,m,p=0; db dp[2][maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { read(n); read(m); For(i,0,n) { p^=1; For(j,0,m) { dp[p][j]=0; if(i) dp[p][j]+=(dp[p^1][j]+1)*(db)i/(i+j); if(j) dp[p][j]+=(dp[p][j-1]-1)*(db)j/(i+j); dp[p][j]=max(dp[p][j],(db)0); } } printf("%.6f\n",dp[p][m]-0.0000005); return 0; }
bzoj3143游走
一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。
当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
n<=500
直接高斯消元,一开始数组没开够WA了很久找不到问题。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=500+7,maxm=2e6+7; int n,m; db D[maxn][maxn],P[maxm],g[maxm],ind[maxn],ans; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } const db eps=1e-14; int dcmp(db x) {return fabs(x)<eps? 0:(x>0? 1:-1);} struct Edge{ int x,y; }edge[maxm]; void Guess() { db r; For(i,1,n) { For(j,i,n) if(dcmp(D[j][i])) { if(i!=j) swap(D[i],D[j]); break; } For(j,i+1,n) { r=D[j][i]/D[i][i]; For(k,i,n+1) D[j][k]-=D[i][k]*r; } } Rep(i,n,1) { For(j,i+1,n) if(dcmp(D[i][j])) D[i][n+1]-=D[i][j]*P[j]; P[i]=D[i][n+1]/D[i][i]; } } int main() { read(n); read(m); int x,y; For(i,1,n) D[i][i]=1; D[1][n+1]=1; For(i,1,m) { read(x); read(y); edge[i].x=x; edge[i].y=y; ++ind[x]; ++ind[y]; if(x!=n&&y!=n) --D[x][y],--D[y][x]; } For(i,1,n) For(j,1,n) if(i!=j) D[i][j]/=ind[j]; Guess(); For(i,1,m) { x=edge[i].x; y=edge[i].y; g[i]+=P[x]/ind[x]; g[i]+=P[y]/ind[y]; } sort(g+1,g+m+1); For(i,1,m) ans+=g[i]*(m-i+1); printf("%.3f\n",ans); return 0; }
bzoj4318 OSU
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=1e5+7; int n; db p[maxn],X[maxn],Y[maxn],Z[maxn],ans; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { read(n); For(i,1,n) scanf("%lf",&p[i]); For(i,1,n) X[i]=(X[i-1]+1)*p[i]; For(i,1,n) Y[i]=(Y[i-1]+2*X[i-1]+1)*p[i]; For(i,1,n) Z[i]=(Z[i-1]+3*Y[i-1]+3*X[i-1]+1)*p[i]; For(i,1,n) ans+=Z[i]*(1-p[i+1]); printf("%.1f\n",ans); return 0; }
bzoj1778驱逐猪猡
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db long double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=300+7,maxm=1e5+7; int n,m; db P,Q,D[maxn][maxn],CS[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[2*maxm],to[2*maxm],e=0; db ind[maxn]; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; to[++e]=x;nxt[e]=fir[y];fir[y]=e; ++ind[x]; ++ind[y]; } const db eps=1e-15; //int dcmp(db x){return fabs(x)<eps? 0:(x>0? 1:-1);} void Guess() { db r;int p; For(i,1,n) { p=i; For(j,i,n) if(fabs(D[j][i])>fabs(D[p][i])) p=j; if(i!=p) swap(D[i],D[p]); For(j,i+1,n) { r=D[j][i]/D[i][i]; For(k,i,n+1) D[j][k]-=D[i][k]*r; } } Rep(i,n,1) { For(j,i+1,n) D[i][n+1]-=D[i][j]*CS[j]; CS[i]=D[i][n+1]/D[i][i]; } } int main() { read(n); read(m); read(P); read(Q); P/=Q; Q=1.0-P; int x,y,z; For(i,1,m) { read(x); read(y); add(x,y); } D[1][n+1]=1; For(i,1,n) { D[i][i]=1; for(y=fir[i];y;y=nxt[y]) { D[i][z=to[y]]-=Q/ind[z]; } } Guess(); For(i,1,n) CS[0]+=CS[i]; For(i,1,n) printf("%.9Lf\n",fabs(CS[i]/CS[0]+eps)); return 0; }
BZOJ1444有趣的游戏
0<=P, n , l, m≤ 10.
注意,题意是,只要游戏没结束,时间一直延长。//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db long double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=500+7,maxt=23,maxm=2*maxn*maxt; const db eps=1e-12; int n,l,m; db P[maxn],D[maxn][maxn],ans[maxn]; char s[maxn]; int son[maxn][maxt],fail[maxn],tot,num[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxm],to[maxm],e=0;db p[maxm]; void add(int x,int y,db z) { x++; y++; // printf("add: %d->%d , %.2Lf\n",x,y,z); to[++e]=y;nxt[e]=fir[x];fir[x]=e;p[e]=z; } void insert(int p) { int now=0,x; For(i,1,l) { x=s[i]-'A'+1; if(!son[now][x]) son[now][x]=++tot; now=son[now][x]; } num[now+1]=p; } int zz[maxn]; void bld() { int s=1,t=0,x,y,z; For(i,1,m) if(son[0][i]) add(0,son[0][i],P[i]),zz[++t]=son[0][i]; while(s<=t) { x=zz[s++]; For(i,1,m) { if(son[x][i]) zz[++t]=son[x][i],fail[son[x][i]]=son[fail[x]][i]; else son[x][i]=son[fail[x]][i]; add(x,son[x][i],P[i]); } } } void Guess(int n) { db r;int p; For(i,1,n) { p=i; For(j,i,n) if(fabs(D[j][i])>fabs(D[p][i])) p=j; if(i!=p) swap(D[i],D[p]); if(fabs(D[i][i])<eps) continue; For(j,i+1,n) { r=D[j][i]/D[i][i]; For(k,i,n+1) D[j][k]-=D[i][k]*r; } } Rep(i,n,1) { For(j,i+1,n) D[i][n+1]-=D[i][j]*P[j]; if(D[i][i]) P[i]=D[i][n+1]/D[i][i]; } } int main() { read(n); read(l); read(m); int x,y,z; For(i,1,m) { read(x); read(y); P[i]=(db)x/(db)y; } For(i,1,n) { scanf("%s",s+1); insert(i); } bld(); tot++; For(i,1,tot) { D[i][i]=1; if(!num[i]) for(y=fir[i];y;y=nxt[y]) D[z=to[y]][i]-=p[y]; } D[1][tot+1]=1; For(i,1,tot) { if(num[i]) D[1][i]=1; else D[1][i]=0; } Guess(tot); For(i,1,tot) if(num[i]) ans[num[i]]=P[i]; For(i,1,n) printf("%.2Lf\n",fabs(ans[i])); return 0; }