【字符串】【高斯消元】【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 */
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/qq_34454069/article/details/83278299
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞