1. 程式人生 > >【字串】【高斯消元】【KMP】BZOJ4820硬幣遊戲

【字串】【高斯消元】【KMP】BZOJ4820硬幣遊戲

分析:

如果資料範圍再小點,可以利用BZOJ1444有趣的遊戲方法來做。

所以這裡為了優化,直接儲存下來從某個字串轉移到另一個的概率即可。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 310
using namespace std;
long double pw[MAXN],tot[MAXN],a[MAXN][MAXN];
char s1[MAXN][MAXN];
int nxt[MAXN]; int n,m; void build(char *s){ tot[0]=pw[m-1]; nxt[0]=-1; for(int i=1;i<m;i++){ int las=nxt[i-1]; while(las!=-1&&s[las+1]!=s[i]) las=nxt[las]; if(s[las+1]==s[i]){ nxt[i]=las+1; tot[i]=tot[las+1]+pw[m-i-1]; } else{ nxt[i]=-1; tot[i]=pw[m-i-1]; } }
/*for(int i=0;i<m;i++) PF("[%lf]",tot[i]); PF("\n");*/ } long double calc(int i,int j){ int now=-1; for(int k=0;k<m;k++){ while(now!=-1&&s1[i][now+1]!=s1[j][k]) now=nxt[now]; if(s1[i][now+1]==s1[j][k]) now++; } if(now!=-1) return tot[now]; return 0; } void gauss(int row,
int col){ int r=0,c=0; for(;r<row&&c<col-1;r++,c++){ int maxr=r; for(int i=r+1;i<row;i++) if(a[i][c]>a[maxr][c]) maxr=i; swap(a[r],a[maxr]); for(int i=0;i<row;i++) if(i!=r){ double t=a[i][c]/a[r][c]; for(int j=c;j<col;j++) a[i][j]=a[i][j]-t*a[r][j]; } } /*for(int i=0;i<row;i++){ for(int j=0;j<col;j++) PF("%lf ",a[i][j]); PF("\n"); }*/ } int main(){ SF("%d%d",&n,&m); pw[0]=1; for(int i=1;i<=m;i++) pw[i]=pw[i-1]*0.5; for(int i=0;i<n;i++) SF("%s",s1[i]); for(int i=0;i<n;i++){ build(s1[i]); for(int j=0;j<n;j++) a[i][j]=calc(i,j); } for(int i=0;i<n;i++) a[i][n]=-pw[m]; for(int i=0;i<n;i++) a[n][i]=1; a[n][n+1]=1; gauss(n+2,n+2); for(int i=0;i<n;i++) PF("%.10Lf\n",a[i][n+1]/a[i][i]); } /* 3 3 THT TTH HTT */