【BZOJ2553】【BeiJing2011】禁忌 AC自动机 矩阵乘法 动态规划

38 篇文章 0 订阅
10 篇文章 0 订阅

我已经醉了。出题人卡精度卡常数都是未知生物啊!!!


已经无心写题解,来个详细的~~~“网址”吧:http://wyfcyx.is-programmer.com/posts/78632.html

我的代码是被卡精度的,我可以附上数据生成器。

不要交我的代码,代码仅供参考思想。


代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 80
#define T 26
#define inf 0x3f3f3f3f
using namespace std;

char s[7][17];
int len[7],n,m,p;
bool able[7];
int check_sonstring(int a,int b) // check whether a is son of b
{
	int i,j,fix;
	for(i=1;i<=len[b]-len[a]+1;i++)
	{
		for(j=0;j<len[a]&&s[a][j+1]==s[b][i+j];j++);
		if(j>=len[a])return len[a]==len[b]?-1:1;
	}
	return 0;
}
void check_string()
{
	int i,j,k;
	scanf("%d%d%d",&n,&m,&p);
	for(i=1;i<=n;i++)scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);
	for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(i!=j)
	{
		k=check_sonstring(i,j);
		if(!k)continue;
		if(k>0)able[j]=1;
		if(k<0&&i<j)continue;
	}
}

struct MRX
{
	long double x[N][N];
}Ini,Trs,I,Std;// 初始矩阵、转移矩阵、空矩阵、标准矩阵
int length;
MRX Mul(const MRX &a,const MRX &b)
{
	MRX C=I;
	for(int i=0;i<=length;i++)
		for(int j=0;j<=length;j++)
			for(int k=0;k<=length;k++)
				C.x[i][j]=C.x[i][j]+b.x[i][k]*a.x[k][j];
	return C;
}
MRX Power(MRX x,int p)
{
	MRX ret=Std;
	while(p)
	{
		if(p&1)ret=Mul(ret,x);
		x=Mul(x,x),p>>=1;
	}
	return ret;
}

struct ACAUTO
{
	int son[N][T],root,cnt;
	bool end[N];
	void insert(int id)
	{
		int i,x=root,alp;
		for(i=1;i<=len[id];i++)
		{
			alp=s[id][i]-'a';
			if(!son[x][alp])son[x][alp]=++cnt;
			x=son[x][alp];
		}
		end[x]=true;
	}
	queue<int>q;
	int fail[N];
	void build_fail()
	{
		while(!q.empty())q.pop();

		int i,u,v;
		q.push(root);
		while(!q.empty())
		{
			u=q.front(),q.pop();
			for(i=0;i<p;i++)
			{
				if(end[u])son[u][i]=son[root][i];
				else if(v=son[u][i])
				{
					if(u==root)fail[v]=0;
					else fail[v]=son[fail[u]][i];
					q.push(v);
				}
				else son[u][i]=son[fail[u]][i];
			}
		}
	}
	void build_matrix()
	{
		int i,j,k;
		Ini.x[0][0]=(long double)1.0;
		for(i=0;i<=cnt;i++)
			for(j=0;j<p;j++)
				Trs.x[son[i][j]][i]=Trs.x[son[i][j]][i]+(long double)1.0/(long double)p;
		cnt++;
		Trs.x[cnt][cnt]=(long double)1.0;
		for(i=0;i<cnt;i++)if(end[i])
			Trs.x[cnt][i]=(long double)1.0;
		for(i=0;i<=cnt;i++)Std.x[i][i]=(long double)1.0;

		length=cnt;
	}
}ac;

int main()
{
	freopen("test.in","r",stdin);
	check_string();

	int i,j,k;
	for(i=1;i<=n;i++)if(able[i]==0)ac.insert(i);
	ac.build_fail();
	ac.build_matrix();

	MRX temp=Power(Trs,m+1);
	MRX final=Mul(Ini,temp);

	long double ans;ans=final.x[length][0];
//	for(i=0;i<length;i++)if(ac.end[i])ans=ans+final.x[i][0];
		double Ans=ans;
	printf("%lf",Ans);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值