Bzoj2553 [BeiJing2011]禁忌

22 篇文章 0 订阅
4 篇文章 0 订阅

题目链接:[BeiJing2011]禁忌

刚刚写了两道AC自动机+DP的傻X题以为自己很NB,然后信心满满的找到了这道题,然后就被艹翻了QAQ

题意都是看着po姐的博客才明白的,语死早……

就是求长度为len的所有串的最大伤害的期望值(平均值)

首先走到每个串都是有一定概率的,走到禁忌串也是,我们令dp[i][j]表示从i节点走到j节点的概率,那么答案就是走到所有禁忌串的概率

发现这样并没有办法统计答案,因此要加一个新点表示所有的禁忌串

然后所有禁忌串向这个点连边,表示走到了禁忌串

同时所有禁忌串向根节点0连边,表示走到禁忌串后返回,因为我们是把串分隔开来统计禁忌串的数目的,所以要回到根节点

那么现在这个图就和普通的邻接矩阵的图十分相似,我们把它len次方后dp[0][新点]就是走到禁忌串的概率和

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define LL long long
#define ld long double
using namespace std;
const int maxn=110;
const int mod=100000;
int n,m,alphabet,L;
char str[maxn];

struct AC_automation{
	int next[maxn][26];
	int end[maxn],fail[maxn];
	int l,root;
	ld dp[80][80],b[80][80];
	int newnode(){
        for (int i=0;i<26;++i) next[l][i]=-1;
        end[l]=fail[l]=0; return l++;
    }
    void init(){
        l=0; root=newnode();
    }
	int idx(char c){
  		return c-'a';
	}
	void ins(char buf[]){
        int now=root,len=strlen(buf);
        for (int i=0;i<len;++i){
            int x=idx(buf[i]);
            if (next[now][x]==-1)
                next[now][x]=newnode();
            now=next[now][x];
        }end[now]=1;
    }
	void build(){
        queue<int>q; fail[root]=root;
        for (int i=0;i<26;++i)
            if (next[root][i]!=-1){
                q.push(next[root][i]);
                fail[next[root][i]]=root;
            }else next[root][i]=root;
        while (!q.empty()){
            int now=q.front(); q.pop();
            for (int i=0;i<26;++i)
                if (next[now][i]!=-1){
                    q.push(next[now][i]);
                    fail[next[now][i]]=next[fail[now]][i];
                    if (end[fail[next[now][i]]]) end[next[now][i]]=1;
                }else next[now][i]=next[fail[now]][i];
        }
    }
    void Init_Matrix(){
		ld addans=1.0/alphabet;
		for (int i=0;i<l;++i)
		    for (int j=0;j<alphabet;++j)
		        if (end[next[i][j]]){
					dp[i][0]+=addans;
					dp[i][l]+=addans;
		        }else dp[i][next[i][j]]+=addans;
		dp[l][l]=1;	b[0][0]=0;
		for (int i=0;i<=l;++i)
		    for (int j=0;j<=l;++j)
		        b[i][j]=i==j;
    }
    void mul(ld a[80][80],ld b[80][80],ld c[80][80]){
		ld tmp[80][80];
		for (int i=0;i<=l;++i)
		    for (int j=0;j<=l;++j){
				tmp[i][j]=0;
				for (int k=0;k<=l;++k)
				    tmp[i][j]+=a[i][k]*b[k][j];
		    }
		for (int i=0;i<=l;++i)
		    for (int j=0;j<=l;++j)
		        c[i][j]=tmp[i][j];
    }
	void Matrix_power(){
		while (L){
			if (L&1) mul(b,dp,b);
			mul(dp,dp,dp); L>>=1;
		}cout<<fixed<<setprecision(15)<<b[0][l];
	}
}Ac;

int main(){
	Ac.init();
	scanf("%d%d%d",&n,&L,&alphabet);
	for (int i=1;i<=n;++i){
		scanf("%s",str);
		Ac.ins(str);
	}
	Ac.build();
	Ac.Init_Matrix();
	Ac.Matrix_power();
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值