BZOJ 2553: [BeiJing2011]禁忌【ACAM + 期望dp + 矩快优化

80 篇文章 0 订阅
6 篇文章 0 订阅

……反正瞎瘠薄搞搞,都是显然的

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define MAXN 80
using namespace std;	int n,m,ji;

struct Matrix{
	long double d[MAXN][MAXN];
	int x,y;
	Matrix():x(0),y(0){memset(d,0,sizeof d);}
	Matrix(int w):x(w),y(w){
		memset(d,0,sizeof d);
		for(int i=0;i<w;++i)	d[i][i] = 1;
	}
	Matrix(int x,int y):x(x),y(y){memset(d,0,sizeof d);}
	
	Matrix operator * (const Matrix ano) {
		Matrix RTN(x,ano.y);
		for(register int i=0;i<x;++i)
			for(register int j=0;j<y;++j)
				for(register int k=0;k<ano.y;++k)
					RTN.d[i][k] += d[i][j] * ano.d[j][k];
		return RTN;
	}
	
	inline Matrix pow(int c){
		Matrix TMP = *this , RTN(x);
		for(;c;c>>=1,TMP=TMP*TMP)
			if(c&1)
				RTN = RTN * TMP;
		return RTN;
	}
	
	void write(){
		puts("");
		for(register int i=0;i<x;++i)
			for(register int j=0;j<y;++j)
				printf("%.0Lf%c",d[i][j],j==y-1?'\n':' ');
		puts("");
	} 
}INIT,TRANS;

long double f[MAXN][MAXN];
long double ans = 0;
long double p;
struct ACAM{
	int son[MAXN][26];
	int cnt_node,root;	
	int fail[MAXN];
	int tag[MAXN];
	
	inline void init(){
		root = cnt_node = 1;
	}
	
	char s[20];
	inline void insert(int now){
		scanf("%s",s);
		for(char *i = s;*i;++i){
			int x = (*i) - 'a';
			if ( !son[now][x] )	son[now][x] = ++cnt_node;
			now = son[now][x];
		}
		tag[now] = 1;
	}
	
	int que[MAXN],head,tail;
	inline void bfs(int now){
		head = tail = 1;
		que[0] = now;
		for(register int x=0;x<ji;++x)
			if(son[now][x])	fail[ son[now][x] ] = now , que[tail++] = son[now][x];
			else	son[now][x] = now;
		while(head^tail){
			now = que[head++];
			for(register int x=0;x<ji;++x)
				if(son[now][x])
					fail[ son[now][x] ] = son[ fail[now] ][x] ,
					que[tail++] = son[now][x] , 
					tag[ son[now][x] ] |= tag[fail[son[now][x]]];
				else	son[now][x] = son[ fail[now] ][x];
		}
	}

	inline void DP(int len){
		++cnt_node;
		INIT = Matrix(cnt_node,1);
		INIT.d[1][0] = 1;
		TRANS = Matrix(cnt_node,cnt_node);
		for(register int i=1;i<cnt_node;++i)
			for(register int x=0;x<ji;++x){
				int aim = son[i][x];
				if(!tag[aim])	TRANS.d[aim][i] += p;
				else{
					TRANS.d[1][i] += p;
					TRANS.d[0][i] += p;
				}
			}
		TRANS.d[0][0] = 1;
		
		INIT = TRANS.pow(len) * INIT;
		printf("%.6Lf",INIT.d[0][0]);
//		f[0][1] = 1;
//		for(int i=0;i<len;++i){
//			for(int j=0;j<tail;++j){
//				int now = que[j];
//				for(int k = 0;k<ji;++k){
//					if(tag[son[now][k]])
//						ans += f[i][now]*p , f[i+1][root] += f[i][now]*p;
//					else	f[i+1][son[now][k]] += f[i][now]*p;
//				}
//			}
//		}
//		printf("%.6Lf",ans);
	}
}YJQ;


int main(){
	YJQ.init();
	scanf("%d%d%d",&n,&m,&ji);
	p = (double)1/ji;
	for(register int i=1;i<=n;++i)	YJQ.insert(YJQ.root);
	YJQ.bfs(YJQ.root);
	YJQ.DP(m);
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值