2553: [BeiJing2011]禁忌

Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge
Submit: 203  Solved: 75
[Submit][Status]

Description

Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平。而后,Koishi恢复了读心的能力……

如今,在John已经成为传说的时代,再次造访那座岛屿的人们却发现Koishi遇到了新麻烦。

这次她遇到了Flandre Scarlet——她拥有可以使用禁忌魔法而不会受到伤害的能力。

为了说明什么是禁忌魔法及其伤害,引入以下概念:

1.字母集A上的每个非空字符串对应了一个魔法。

其中A是包含了前alphabet个小写字母的集合。

2.有一个集合T,包含了N个字母集A上的字符串

T中的每一串称为一个禁忌串(Taboo string)

3.一个魔法,或等价地,其对应的串s因为包含禁忌而对使用者造成的伤害按以下方式确定:

把s分割成若干段,考虑其中是禁忌串的段的数目,不同的分割可能会有不同的数目,其最大值就是这个伤害。

由于拥有了读心的能力,Koishi总是随机地使用Flandre Scarlet的魔法,可以确定的是,她的魔法正好对应字母集A上所有长度为len的串。

但是,Flandre Scarlet所使用的一些魔法是带有禁忌的,由于其自身特性,她可以使用禁忌魔法而不受到伤害,而Koishi就不同了。可怜的Koishi每一次使用对方的魔法都面临着受到禁忌伤害的威胁。

你现在需要计算的是如果Koishi使用对方的每一个魔法的概率是均等的,那么每一次随机使用魔法所受到的禁忌伤害的期望值是多少。

Input

第一行包含三个正整数N、len、alphabet。

接下来N行,每行包含一个串Ti,表示禁忌串。

Output

一个非负实数,表示所受到禁忌伤害的期望值。

Sample Input

2 4 2

aa

abb

Sample Output

0.75

【样例1解释】
一共有2^4 = 16种不同的魔法。

需要注意的是“aabb”的禁忌伤害是1而不是2。

HINT

100%的数据中N ≤ 5,len ≤109,1 ≤ alphabet ≤ 26。

在所有数据中,有不少于40%的数据中:N = 1。

数据保证每个串Ti的长度不超过15,并且不是空串。

数据保证每个Ti均仅含有前alphabet个小写字母。

数据保证集合T中没有相同的元素,即对任意不同的i和j,有Ti≠Tj。

【评分方法】

对于每一组数据,如果没有得到正确的输出(TLE、MLE、RTE、输出格式错误等)得0分。

否则:设你的输出是YourAns,标准输出是StdAns:

记MaxEPS = max(1.0 , StdAns)×10-6

如果|YourAns – StdAns| ≤ MaxEPS则得10分,否则得0分。

即:你的答案需要保证相对误差或绝对误差不超过10-6。

题解:

出题人果然丧心病狂卡精度。。。

这题写题解的人好像不多,也许是我太傻叉了,时光机的代码画面太美我都不敢看了。。。

首先我们先搞清一个问题,如果给定了一个字符串,那么它的伤害指数是多少。

转化一下就变成 在一个数轴上给定若干条线段,请选出最多的线段并且使得这些线段两两交集为空。

然后这就是一个贪心水题,见http://www.cnblogs.com/zyfzyf/p/4006703.html

我们只要按右端点排序,能取就取。

那假如我们已经构建了一个AC自动机,我们只要走到一个危险节点,就ans++,并且退回到根节点重新开始走。

可以看出,这样正好相当于在模拟上面的贪心过程。

然后我们看看len增加1,我们能干什么

建图如下:

void build()
{
vis[]=;
q.push();long double tmp=1.0/k;
while(!q.empty())
{
int x=q.front();q.pop();
for0(i,k-)
{
if(!vis[t[x][i]])vis[t[x][i]]=,q.push(t[x][i]);
if(v[t[x][i]])
{
a.d[x][n]+=tmp;
a.d[x][]+=tmp;
}else a.d[x][t[x][i]]+=tmp;
}
}
}

意思就是我们把所有这样的关系找出来,如果len结束时,我们在x。

那如果t[x][i]是根节点,那我们就有1.0/alp的期望使ans+1,并返回根节点,否则我们有1.0/alp的期望走到t[x][i]。

最后我们求长度为给定是从1走到ans(设置为节点n)的期望次数即可。

然后这个矩阵构建出来我们发现 i到j的期望就等于sigma(i到k的期望*k到j的期望)。

这正好是矩阵乘法!

然后我们就可用快速幂加速了。

注意设置a[n][n]=1

代码:

 #include<cstdio>

 #include<cstdlib>

 #include<cmath>

 #include<cstring>

 #include<algorithm>

 #include<iostream>

 #include<vector>

 #include<map>

 #include<set>

 #include<queue>

 #include<string>

 #define inf 1000000000

 #define maxn 200+5

 #define eps 1e-10

 #define ll long long

 #define pa pair<int,int>

 #define for0(i,n) for(int i=0;i<=(n);i++)

 #define for1(i,n) for(int i=1;i<=(n);i++)

 #define for2(i,x,y) for(int i=(x);i<=(y);i++)

 #define for3(i,x,y) for(int i=(x);i>=(y);i--)

 #define mod 1000000007

 using namespace std;

 inline int read()

 {

     int x=,f=;char ch=getchar();

     while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}

     while(ch>=''&&ch<=''){x=*x+ch-'';ch=getchar();}

     return x*f;

 }
int n,m,k,cnt,t[maxn][],go[maxn];
bool v[maxn],vis[maxn];
queue<int>q;
char s[maxn];
struct matrix
{
long double d[maxn][maxn];
matrix(){memset(d,,sizeof(d));}
}a,b,c;
inline void add()
{
scanf("%s",s+);int len=strlen(s+),now=;
for1(i,len)
{
int x=s[i]-'a';
if(!t[now][x])t[now][x]=++cnt;
now=t[now][x];
}
v[now]=;
}
void bfs()
{
q.push();
while(!q.empty())
{
int x=q.front(),y,j;q.pop();
v[x]|=v[go[x]];
for0(i,k-)
{
j=go[x];
while(j&&!t[j][i])j=go[j];
if(t[x][i])
{
go[y=t[x][i]]=j?t[j][i]:;
q.push(y);
}else t[x][i]=j?t[j][i]:;
}
}
}
void build()
{
vis[]=;
q.push();long double tmp=1.0/k;
while(!q.empty())
{
int x=q.front();q.pop();
for0(i,k-)
{
if(!vis[t[x][i]])vis[t[x][i]]=,q.push(t[x][i]);
if(v[t[x][i]])
{
a.d[x][n]+=tmp;
a.d[x][]+=tmp;
}else a.d[x][t[x][i]]+=tmp;
}
}
}
inline matrix operator *(matrix &x,matrix &y)
{
matrix z;
for1(i,n)
for1(j,n)
for1(l,n)
z.d[i][j]+=x.d[i][l]*y.d[l][j];
return z;
}
void ksm(int cs)
{
for(;cs;cs>>=,a=a*a)
if(cs&)b=b*a;
}
void printb()
{
for1(i,n)for1(j,n)cout<<i<<' '<<j<<' '<<b.d[i][j]<<endl;
}
void printa()
{
for1(i,n)for1(j,n)cout<<i<<' '<<j<<' '<<a.d[i][j]<<endl;
} int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); n=read();m=read();k=read();cnt=;
for1(i,n)add();
bfs();
n=cnt+;
build();
for1(i,n)b.d[i][i]=;
a.d[n][n]=;
ksm(m);
printf("%.7f\n",(double)b.d[][n]); return ; }

真是一道综合性的难题+好题!

UPD:以上纯属口胡。。。

一个边权为1的邻接矩阵自乘n次,则a[s][t]代表从s恰好经过n条边到t的路径条数。

根据这一点我们可以推广

令a[i][j]表示一步从i到j的期望,那么a自乘n次就a[s][t]就代表从s恰好经过n条边到达t的期望。

然后我们新建了一给点n=cnt+1

然后我们要求sigma(从1到n恰好经过j条边的期望)j<=len

所以我们要设值a[n][n]=1,因为下一次计算的时候b[1][n]=。。。+b[1][n]*a[n][n]+。。。就可以把上一次的答案累计。

就算是我懂了QAQ

BZOJ2553: [BeiJing2011]禁忌的更多相关文章

  1. [BZOJ2553][BeiJing2011]禁忌 dp+AC自动机+矩阵快速幂

    2553: [BeiJing2011]禁忌 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1206  Solved ...

  2. BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵

    原文链接http://www.cnblogs.com/zhouzhendong/p/8196279.html 题目传送门 - BZOJ2553 题意概括 引用一下lych大佬的: 在字母只有前alph ...

  3. BZOJ2553[BeiJing2011]禁忌——AC自动机+概率DP+矩阵乘法

    题目描述 Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平.而后,Koishi恢复了读心的能力…… 如今,在John已经成为传 ...

  4. BZOJ2553 Beijing2011禁忌(AC自动机+动态规划+矩阵快速幂+概率期望)

    考虑对一个串如何分割能取得最大值.那么这是一个经典的线段覆盖问题,显然每次取右端点尽量靠前的串.于是可以把串放在AC自动机上跑,找到一个合法串后就记录并跳到根. 然后考虑dp.设f[i][j]表示前i ...

  5. BZOJ2553 [BeiJing2011]禁忌 【AC自动机 + dp + 矩乘优化】

    题目链接 BZOJ2553 题解 话说在前,此题卡精度,最好开long double 先建\(AC\)自动机 求期望,逆着求,设\(f[i][j]\)为长度为\(i\)的串,当前匹配AC自动机\(j\ ...

  6. 【BZOJ】2553: [BeiJing2011]禁忌 AC自动机+期望+矩阵快速幂

    [题意]给定n个禁忌字符串和字符集大小alphabet,保证所有字符在集合内.一个字符串的禁忌伤害定义为分割能匹配到最多的禁忌字符串数量(一个可以匹配多次),求由字符集构成的长度为Len的字符串的期望 ...

  7. 【BZOJ2553】[BeiJing2011]禁忌 AC自动机+期望DP+矩阵乘法

    [BZOJ2553][BeiJing2011]禁忌 Description Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平. ...

  8. 【bzoj2553】[BeiJing2011]禁忌

    2553: [BeiJing2011]禁忌 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 595  Solved: ...

  9. bzoj 2553 [BeiJing2011]禁忌——AC自动机+概率DP+矩阵

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2553 看了题解才会…… 首先,给定一个串,最好的划分方式是按禁忌串出现的右端点排序,遇到能填 ...

随机推荐

  1. strcpy函数导致release版程序崩溃

    最近在写一个读取模型文件的小程序.很随意的使用了strcpy函数进行char字符数组的拷贝,这个数组是需要传递给PostMessage作为WPARAM的参数.代码部分如下: char pStrCurr ...

  2. 学习redis-安装和基本一些命令

    redis安装 linux下环境安装redis,我这里下载的是3.0.0版本(目前最新版3.2.0). $ wget http://download.redis.io/releases/redis-3 ...

  3. DB2数据库中提高INSERT性能详解

        分类: Linux INSERT 处理过程概述 首先让我们快速地看看插入一行时的处理步骤.这些步骤中的每一步都有优化的潜力,对此我们在后面会一一讨论. 在客户机准备 语句.对于动态 SQL,在 ...

  4. VS2010 EntityFramework Database First

    本文演练介绍如何使用实体框架进行 Database First 开发.通过 Database First,可以从现有数据库对模型进行反向工程处理.模型存储在一个 EDMX 文件(扩展名为 .edmx) ...

  5. Entity Framework 插入数据 解决主键非自增问题

    http://blog.csdn.net/educast/article/details/8632806 与Entity Framework相伴的日子痛并快乐着.今天和大家分享一下一个快乐,两个痛苦. ...

  6. Websocket协议之握手连接

    Websocket协议是为了解决web即时应用中服务器与客户端浏览器全双工通信的问题而设计的,是完全意义上的Web应用端的双向通信技术,可以取代之前使用半双工HTTP协议而模拟全双工通信,同时克服了带 ...

  7. 七,WPF的元素绑定

    数据绑定是一种关系,该关系告诉WPF从一个源对象提取一些信息,并使用这些信息设置目标对象的属性,目标属性总是依赖项属性,然而,源对象可以是任何内容. 源对象是WPF元素并且源属性是依赖项属性的数据绑定 ...

  8. hdu 3591 The trouble of Xiaoqian

    hdu 3591  The trouble of Xiaoqian 题意:xiaoqi要买一个T元的东西,当前的货币有N种,xiaoqi对于每种货币有Ci个:题中定义了最小数量即xiaoqi拿去买东西 ...

  9. 2014年度辛星css教程夏季版第二节

    第一节我们简介了一下CSS的工作流程,我相信读者会有一个大体的认识,那么接下来我们将会深入的研究一下CSS的细节问题,这些问题的涉及将会使我们的工作更加完善. *************注释***** ...

  10. 转载:PCB名詞解釋:通孔、盲孔、埋孔

    在[電子製造業]打滾多年,分享 SMT.焊錫.塑膠射出.產品設計.瓦楞包裝…等經驗.請注意文章內容不見得都正確,服用前請三思… 之前有網友提醒我有篇文章把PCB的盲孔(Blind hole).埋孔(B ...