zoukankan      html  css  js  c++  java
  • luogu P6125 [JSOI2009]有趣的游戏

    LINK:有趣的游戏

    直接说做法了。首先是 我是不会告诉你我看完题后不太会 摸了2h鱼后看题解 一直翻发现自己题目有些没读完整。。

    题目中说了每个字符串长度相同 而我一直在思考AC自动机可能存在一些节点是不合法的且其还是其他节点的fail节点这个时候我很茫然不知道怎么dp了。。

    实际上 长度相同那么一定不存在上述情况 发生 那么久很好解决了 我们很容易就可以列出来概率矩阵。

    显然是存在一些环的问题的 对于终止节点我们定义其不向其他节点做出概率贡献。

    然后我们利用这个矩阵不断的自乘进行概率的转移 最后会不断收敛 最后就是第一行的值了 (至于为什么 自己思考。

    当然我们也应该知道这个应该是收敛的 因为可以考虑两种情况 多种概率不断交换的 但是其值不变的 乘多少次都无效。 对于概率改变的 我们自乘矩阵几十次也相当于一个矩阵被我们乘了2^几十次 这个是非常庞大的所以该转移的概率显然也转移完了 我们把后面的精度忽略掉就是正确答案。

    当然这个思路并不是那么顺畅 比较顺的是 高斯消元啊 遇到有环的问题 首选高消且这个数据范围还支持高消。

    设f[i]表示到达第i个点的期望次数 列出来i的转移方程。

    可以发现 f[0]=1+... 因为初始是1 我们将这n个方程组解一下即可得到到达每个点的期望次数。同时注意终止节点始终不贡献转移。

    可以发现最后求的是概率 感性的理解 这里的期望次数其实就是概率 可以这样考虑 我们初始只有f[0]=1 这个表示了0被期望经过的次数。

    除了0这个节点 其余的所有节点都是从0出发来经过的 0到他们的期望次数显然<1 且 这是和概率有关的 概率*结果=次数 我们发现这个结果被定义为单位1了即经过就是经过了 没有经过就没有经过 所以此处概率等于次数。

    综上这道题两种方法均可。

    const int MAXN=110;
    int n,m,l,cnt;
    char ch[MAXN];
    int t[MAXN][10],fail[MAXN],pos[MAXN],c[MAXN],q[MAXN];
    db a[MAXN][MAXN],p[MAXN];
    inline void get_fail()
    {
    	int l=0,r=0;
    	for(int i=0;i<m;++i)if(t[0][i])q[++r]=t[0][i];
    	while(++l<=r)
    	{
    		int x=q[l];
    		for(int i=0;i<m;++i)
    		{
    			if(t[x][i])fail[t[x][i]]=t[fail[x]][i],q[++r]=t[x][i];
    			else t[x][i]=t[fail[x]][i];
    		}
    	}
    }
    inline void GAUSS()//普通高消
    {
    	for(int i=0;i<=cnt;++i)//寻找第i个主元
    	{
    		int p=i;
    		for(int j=i+1;j<=cnt;++j)
    			if(fabs(a[j][i])>fabs(a[p][i]))p=j;
    		if(i!=p)rep(0,cnt+1,j)swap(a[p][j],a[i][j]);
    		for(int j=0;j<=cnt;++j)//约旦消元
    		{
    			if(i==j)continue;
    			db d=a[j][i]/a[i][i];
    			for(int k=0;k<=cnt+1;++k)a[j][k]-=a[i][k]*d;
    		}
    	}
    	rep(0,cnt,i)a[i][cnt+1]/=a[i][i];
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	gt(n);gt(l);gt(m);
    	rep(1,m,i)
    	{
    		int x,y;gt(x);gt(y);
    		p[i-1]=(db)x/y;
    	}
    	rep(1,n,i)
    	{
    		scanf("%s",ch+1);
    		int p=0;
    		rep(1,l,j)
    		{
    			int w=ch[j]-'A';
    			if(!t[p][w])t[p][w]=++cnt;
    			p=t[p][w];
    		}
    		pos[i]=p;c[p]=1;
    	}
    	get_fail();
    	for(int i=0;i<=cnt;++i)
    	{
    		a[i][i]+=-1;
    		if(c[i])continue;
    		for(int j=0;j<m;++j)
    		{
    			int tn=t[i][j];
    			//cout<<i<<' '<<tn<<endl;
    			a[tn][i]+=p[j];
    		}
    	}
    	a[0][cnt+1]=-1;
    	//rep(0,cnt,i){rep(0,cnt+1,j)cout<<a[i][j]<<' ';cout<<endl;}
    	GAUSS();
    	rep(1,n,i)if(fabs(a[pos[i]][cnt+1])<EPS)puts("0.00");else printf("%.2lf
    ",a[pos[i]][cnt+1]);
    	return 0;
    }
    
  • 相关阅读:
    RESTful API设计指南(转载)
    理解RESTful架构(转载)
    什么是FreeMaker?
    为了梦,向前冲!
    php时间输出结果减去一分钟
    利用css+js制作下拉列表
    zzz的口胡记
    UOJ507. 【JOISC2020】星座3(贪心)
    vim使用小记
    UOJ#62【UR #5】怎样跑得更快(反演)
  • 原文地址:https://www.cnblogs.com/chdy/p/12464619.html
Copyright © 2011-2022 走看看