题意
给定m个长度为n的字符串,记s,且si,j∈[A,C,G,T,?]
随机构建一个仅含[A,C,G,T]的长度为n的字符串t
求t能和其中任意一个si匹配的概率
t和si匹配定义为存在一种将si的?
转换的方式使得si=t
1≤n≤100 , 1≤m≤40
概率允许5%的误差,注意P=0不合法
Solution
因为分母过于强大(4100),正经的概率计算大概率会出问题。
注意到概率误差非常宽松,我们可以乱搞抽样调查
一个t的贡献可以视为对第一个与t匹配的si贡献+1
所以对于每一个si,构造若干个和si匹配的t,对si造成贡献仅当t和si匹配但不和s1...i−1匹配
设样本空间大小为k,随机构造能和si匹配的概率为p1,造成贡献的样本数量为f,则总贡献为
kp1×f
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include<bits/stdc++.h> using namespace std; const int mxn=110; typedef long double ldb; void cal_t(string a); bool check(string a,string b); int n,m; string s[mxn]; string ver="ACGT"; string t; ldb val[mxn]; ldb ans; int main() { srand(time(NULL)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) cin>>s[i]; for(int i=1;i<=m;i++) { ldb u=0,v=1; bool flag=0; for(int j=0;j<n;j++) if(s[i][j]!='?') v/=4.0; for(int p=1;p<=6123;p++) { cal_t(s[i]); flag=0; for(int k=1;k<i;k++) { if(check(s[k],t)) { flag=1; break; } } if(!flag) u+=1.0; } ans=ans+(u*v/6123.0); } printf("%.80Lf\n",ans); }
bool check(string a,string b) { for(int i=0;i<n;i++) { if(a[i]=='?') continue; if(a[i]!=b[i]) return false; } return true; }
void cal_t(string a) { t=""; for(int i=0;i<n;i++) { char in; if(a[i]=='?') in=char(ver[(rand()%4)]); else in=char(a[i]); t+=in; } }
|