码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2553: [BeiJing2011]禁忌

时间:2015-04-13 16:10:25      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:

求所有长度为 len 的串s中,最多包含多少个不重叠的子串, 的期望。

开始觉得把s分成若干段这个操作让人无法下手, 但是其实一个简单的贪心就可以了, 因为如果所有子串不互相包涵的话, 一定是能取就取, 如果没有特殊限制的话, 可以把所有包含另一个子串的子串直接删掉或者是在建ac自动机的时候把end传下去(这样记录以当前点为后缀的串中是否含有一个子串)就可以了。

期望 = 这个状态出现的概率 * 贡献(恒为1)

所以就转化成了一个概率dp的问题。

此类题经典的转移状态: f[当前长度][当前在哪里], 然后枚举下一个字符是谁。

10^9 的长度第一维显然是存不下的, 所以要用矩乘来优化

算出f[i][j] 表示从i点走一步到j点的概率, 如果下一个走到的点 end == 1的话就跳回root 就好了。

但是要统计这样跳了多少次,  怎么办呢?

这里有一个小技巧就是单开了一个点T记录这个次数, 每次把下一个点转移到root的时候也转移到这个点上一份, 这样每走完一步这个点的值就是有多少个点在这里跳回了root, 而如果要统计所有步的话就要把每一步的这个值累加起来, 其实只要把 f[T][T] 赋成1就行了。

另外一个问题是这道题 double 是过不去的, 要开long double , 可是我始终get不到long double 应该怎么输出,, %f, %lf, %Lf, %llf 全都不行啊,,,最后强制转化成double 输出了 T T

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#define MAXN 105
using namespace std;
int n, len, lala, root, cnt, next[MAXN][27];
int end[MAXN], fail[MAXN];
struct Matrix{
    long double a[MAXN][MAXN];
    Matrix(){
        for(int i = 0; i <= cnt + 1; i ++)
            for(int j = 0; j <= cnt + 1; j ++)
                a[i][j] = 0.0;    
    }    
}f, ans;
Matrix cheng(Matrix a, Matrix b){
    Matrix tmp;
    for(int i = 1; i <= cnt + 1; i ++)
        for(int k = 1; k <= cnt + 1; k ++)
            for(int j = 1; j <= cnt + 1; j ++)
                (tmp.a[i][j] += a.a[i][k] * b.a[k][j]);
    return tmp;     
}
char s[22];
int newnode(){
    cnt ++;
    memset(next[cnt], -1, sizeof(next[cnt]));
    return cnt;    
}
void insert(){
    int len = strlen(s + 1), now = root;
    for(int i = 1; i <= len; i ++){
        int c = s[i] - ‘a‘;
        if(next[now][c] == -1) next[now][c] = newnode();
        now = next[now][c];
    } end[now] = 1;
}
queue <int> q;
void build(){
    fail[root] = root;
    int p = root;
    for(int i = 0; i < lala; i ++)
        if(next[p][i] == -1) next[p][i] = root;
        else fail[next[p][i]] = root, q.push(next[p][i]);
    while(!q.empty()){
        p = q.front(); q.pop();
        for(int i = 0; i < lala; i ++)
            if(next[p][i] == -1) next[p][i] = next[fail[p]][i];
            else fail[next[p][i]] = next[fail[p]][i], q.push(next[p][i]), end[next[p][i]] |= end[next[fail[p]][i]];    
    }
}
int main(){
    scanf("%d%d%d", &n, &len, &lala);
    root = newnode();
    for(int i = 1; i <= n; i ++){
        scanf("%s", s + 1);
        insert();    
    }
    build();
    int T = cnt + 1;
    long double ha = (long double)1.0 / lala;
    for(int i = 1; i <= cnt; i ++){
        for(int c = 0; c < lala; c ++)
            if(end[next[i][c]]){
                f.a[i][1] += ha; f.a[i][T] += ha;   
            }    
            else f.a[i][next[i][c]] += ha;
    }
    f.a[T][T] = 1;
    for(int i = 1; i <= cnt + 1; i ++)
        ans.a[i][i] = 1.0;
    while(len){
        if(len & 1)ans = cheng(ans, f);
        f = cheng(f, f);
        len >>= 1;    
    }
    printf("%.8f\n", (double)ans.a[1][T]);
	return 0;
}

 

bzoj 2553: [BeiJing2011]禁忌

标签:

原文地址:http://www.cnblogs.com/lixintong911/p/4422289.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!