ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4569 [BJWC2011]禁忌

2021-03-14 17:03:15  阅读:220  来源: 互联网

标签:int P4569 禁忌 BJWC2011 son long pair using define


题目传送门

题意简述:给出大小为 \(n\) 的字典 \(s\)。设函数 \(g(t)\) 表示 \(t\) 最多能被分割成的单词个数。等概率随机生成长度为 \(len\) 的字符串 \(T\),求 \(E(g(t))\)。

hot tea. 比较像 P3193 [HNOI2008]GT考试


首先对 \(s_i\) 建出 ACAM,然后在上面 DP。设 \(f_{i,j}\) 表示关于所有 \(T\)(\(|T|=i\) 且 \(T\) 在 ACAM 上能跑到状态 \(j\))的一个东西。那么究竟是表示什么呢?

记 \(P=\dfrac{f_{i,j}}{a}\);\(p\) 为 \(j\) 的所有子节点,即 \(p\in son_j\)。

错误思路:如果 \(f_{i,j}\) 单纯表示字符串 \(T\) 的 “概率”(即 \(\dfrac{num(T)}{a^i}\)),那么转移与统计答案就是:如果 \(p\) 是终止节点,将 \(ans\) 加上 \(P\);同时将所有 \(f_{i+1,p}\) 加上 \(P\)。不错,如果 \(g(T)\) 表示的是所有单词 \(s_i\) 在 \(T\) 中出现次数之和,那么这样是没错的,可惜不是,因为会有重复计算,即若字典 \(s=\{\texttt{ab,bc}\}\),那么 \(T=\{\texttt{abc}\}\) 会算入两次贡献(样例中也有提到这种情况)。

正确思路:注意到这个 "最多" 有点麻烦,不过还是有处理的办法:如果 \(p\) 是一个终止节点,那么在下传概率的时候,将 \(f_{i+1,0}\)(而不是 \(f_{i+1,p}\))加上 \(P\)。如果成功匹配一个单词,就必须从头开始匹配。

注意到 \(\sum |s_i|\) 很小,只有 \(75\)。这也意味着 \(j\) 的范围只有 \(75\)。因此,用矩阵快速幂加速 DP 即可,别忘了在矩阵中留个位置记录 \(ans\)。

总时间复杂度 \(\mathcal{O}((\sum T)^3\log len)\)。

/*
	Powered by C++11.
	Author : Alex_Wei.
*/

#include <bits/stdc++.h>
using namespace std;

//#pragma GCC optimize(3)
//#define int long long

using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using db = double;
using ld = long double;
using pii = pair <int,int>;
using pll = pair <ll,ll>;
using pdd = pair <double,double>;
using vint = vector <int>;
using vpii = vector <pii>;

#define fi first
#define se second
#define pb emplace_back
#define mpi make_pair
#define all(x) x.begin(),x.end()
#define sor(x) sort(all(x))
#define rev(x) reverse(all(x))
#define mem(x,v) memset(x,v,sizeof(x))
#define mcpy(x,y) memcpy(x,y,sizeof(y))

const int N=77;
const int S=26;

int sz,al,son[N][S],fa[N],ed[N];
void ins(string s){
	int p=0;
	for(char it:s){
		if(!son[p][it-'a'])son[p][it-'a']=++sz;
		p=son[p][it-'a'];
	} ed[p]=1;
}
void build(){
	queue <int> q;
	for(int i=0;i<al;i++)if(son[0][i])q.push(son[0][i]);
	while(!q.empty()){
		int t=q.front(); q.pop();
		for(int i=0;i<al;i++)
			if(son[t][i])q.push(son[t][i]),fa[son[t][i]]=son[fa[t]][i];
			else son[t][i]=son[fa[t]][i];
		ed[t]|=ed[fa[t]];
	}
}
struct mat{
	ld a[N][N];
	friend mat operator * (mat x,mat y){
		mat z; mem(z.a,0);
		for(int i=0;i<=sz;i++)
			for(int j=0;j<=sz;j++)
				for(int k=0;k<=sz;k++)
					z.a[i][j]+=x.a[i][k]*y.a[k][j];
		return z;
	}
}base,ans;

int n,len;
int main(){
	cin>>n>>len>>al;
	for(int i=0;i<n;i++){
		string s;
		cin>>s,ins(s);
	} build();
	for(int i=0;i<=sz;i++)
		for(int j=0;j<al;j++){
			int p=son[i][j];
			if(ed[p])base.a[i][0]+=1.0/al,base.a[i][sz+1]+=1.0/al;
			else base.a[i][p]+=1.0/al;
		}
	sz++,ans.a[0][0]=base.a[sz][sz]=1;
	while(len){
		if(len&1)ans=ans*base;
		base=base*base,len>>=1;
	} printf("%.10Lf\n",ans.a[0][sz]);
	return 0;
}

标签:int,P4569,禁忌,BJWC2011,son,long,pair,using,define
来源: https://www.cnblogs.com/alex-wei/p/P4569.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有