把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P6125 [JSOI2009] 有趣的游戏

题面传送门
首先这种多字符串匹配的问题想到建立AC自动机。
我们发现自动机上的节点数目只有100个,因此看上去\(O(n^3)\)的东西可以接受。
不难想到高斯消元,但是如果我们设\(f_i\)\(i\)走到的概率那么就有点问题:
因为\(f_0\)一定是\(1\),会有\(n+1\)个方程和\(n\)个变量,不一定有解。
因此我们设\(f_i\)\(i\)经过的期望次数,那么\(f_i\)就不一定是\(0\),那么就只有\(n\)个方程,且\(f_0\)有一个系数\(1\),就不会全部为0了。
时间复杂度\(O((nl)^3)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100+5)
#define M (10+5)
#define K (350)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,l,m,Id[N],p[N],q[N],cnt;char c[N];db F[N][N],ans[N];
namespace AC{
	int x,son[N][M],Fi[N],Fl[N];queue<int> Q;I int Ins(){x=0;for(int i=1;i<=l;i++) !son[x][c[i]-'A']&&(son[x][c[i]-'A']=++cnt),x=son[x][c[i]-'A'];Fl[x]=1;return x;}
	I void BFS(){
		int i,j;for(i=0;i<m;i++) son[0][i]&&(Q.push(son[0][i]),Fi[son[0][i]]=0);while(!Q.empty()){x=Q.front();Q.pop();
			for(i=0;i<m;i++) son[x][i]?(Q.push(son[x][i]),Fi[son[x][i]]=son[Fi[x]][i]):(son[x][i]=son[Fi[x]][i]);
		}for(i=0;i<=cnt;i++) {F[i][i]=1;if(Fl[i]) continue;for(j=0;j<m;j++) F[son[i][j]][i]+=-p[j]*1.0/q[j];}
	}
}
int main(){
	freopen("1.in","r",stdin);
	int i,j,h;scanf("%d%d%d",&n,&l,&m);for(i=0;i<m;i++) scanf("%d%d",&p[i],&q[i]);for(i=1;i<=n;i++) scanf("%s",c+1),Id[i]=AC::Ins();AC::BFS();
	F[0][cnt+1]=1;for(i=0;i<=cnt;i++){
		for(j=i+1;j<=cnt;j++) abs(F[j][i])>abs(F[i][i])&&(swap(F[j],F[i]),0);db pus=F[i][i];for(j=i;j<=cnt+1;j++) F[i][j]/=pus;
		for(j=i+1;j<=cnt;j++) {pus=F[j][i];for(h=i;h<=cnt+1;h++) F[j][h]-=pus*F[i][h];}
	}for(i=cnt;~i;i--){ans[i]=F[i][cnt+1];for(j=i+1;j<=cnt;j++) ans[i]-=F[i][j]*ans[j];}
	for(i=1;i<=n;i++) printf("%.2lf\n",ans[Id[i]]);
}
posted @ 2022-07-04 18:42  275307894a  阅读(24)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end