zoukankan      html  css  js  c++  java
  • [Sdoi2017]硬币游戏 [高斯消元 KMP]

    [Sdoi2017]硬币游戏

    题意:硬币序列,H T等概率出现,(n le 300)个人猜了一个长为$ m le 300$的字符串,出现即获胜游戏结束。求每个人获胜概率


    考场用了[1444: Jsoi200]有趣的游戏的做法,40分

    标解好神!

    思想就是用N表示所有没有人获胜的状态,然后列方程

    对于A,B两个串

    例如:

    A=TTH, B=HTT

    那么N+TTH一定会到终止点,但不一定TTH加完后才停止

    NTTH = A + BH + BTH

    0.125N = A + 0.75B

    获胜概率和为1

    n+1个变量 n+1个方程 高斯消元

    怎么解释呢?

    就是把一些状态的概率用一些变量表示出来了呀

    计算系数可以两两用kmp,求B再方程A中的系数:AB连起来求fail,然后得到后缀=前缀了

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=305;
    const double eps=1e-10;
    inline int read() {
    	char c=getchar(); int x=0, f=1;
    	while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
    	while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    	return x*f;
    }
    
    int n, m;
    char s[N][N];
    double a[N][N], two[N];
    namespace kmp {
    	char s[N<<1];
    	int fail[N];
    	void build(char *s, int n) {
    		fail[1] = 0;
    		for(int i=2; i<=n; i++) {
    			int now = fail[i-1];
    			while(now && s[i] != s[now+1]) now = fail[now];
    			fail[i] = s[i]==s[now+1] ? now+1 : 0;
    		}
    	}
    	double cal(char *a, char *b) {
    		int n = m<<1;
    		for(int i=1; i<=m; i++) s[i] = a[i];
    		for(int i=1; i<=m; i++) s[i+m] = b[i];
    		build(s, n);
    		//for(int i=1; i<=n; i++) printf("%d ", fail[i]); puts("");
    		int now = fail[n]; double ans = 0;
    		while(now) ans += two[m-now], now = fail[now];
    		//printf("ans %lf
    ", ans);
    		return ans;
    	}
    }
    
    void build() {
    	two[0]=1;
    	for(int i=1; i<=m; i++) two[i] = two[i-1] * 0.5;
    
    	for(int i=1; i<=n; i++) a[n+1][i] = 1;
    	a[n+1][n+2] = 1;
    	for(int i=1; i<=n; i++) {
    		for(int j=1; j<=n; j++) a[i][j] = kmp::cal(s[i], s[j]);
    		a[i][n+1] = -two[m];
    	}
    }
    
    void gauss(int n) {
    	//for(int i=1; i<=n; i++) for(int j=1; j<=n+1; j++) printf("%lf%c", a[i][j], j==n+1 ? '
    ' : ' ');
    	for(int i=1; i<=n; i++) {
    		int r=i;
    		for(int k=i; k<=n; k++) if(abs(a[k][i]) > abs(a[r][i])) r=k;
    		if(r != i) for(int j=i; j<=n+1; j++) swap(a[r][j], a[i][j]);
    
    		for(int k=i+1; k<=n; k++) {
    			double t = a[k][i] / a[i][i];
    			for(int j=i; j<=n+1; j++) a[k][j] -= t * a[i][j];
    		}
    	}
    	for(int i=n; i>=1; i--) {
    		for(int j=n; j>i; j--) a[i][n+1] -= a[i][j] * a[j][n+1];
    		a[i][n+1] /= a[i][i];
    	}
    }
    int main() {
    	freopen("game.in", "r", stdin);
    	freopen("game.out", "w", stdout);
    	n=read(); m=read();
    	for(int i=1; i<=n; i++) scanf("%s", s[i]+1);
    	build();
    	gauss(n+1);
    	for(int i=1; i<=n; i++) printf("%.10lf
    ", a[i][n+2]);
    }
    
    
  • 相关阅读:
    小程序工程化探索:大规模场景下的问题和解决方案----------------引用
    对Taro Next小程序跨框架开发的探索与实践-----------------引用
    对Node.js 中的依赖管理------------引用
    对redux的研究--------引用
    JavaScript 中的 for 循环---------------引用
    对JavaScript 模块化的深入-----------------引用
    对Webpack 应用的研究-----------------引用
    webpack5持久化缓存
    设置x 轴斜体(每次我都百度,这次单独为它发一个)
    字典元组列表常用方法
  • 原文地址:https://www.cnblogs.com/candy99/p/6701221.html
Copyright © 2011-2022 走看看