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

bzoj 2806: [Ctsc2012]Cheat 熟悉的文章

时间:2015-01-11 12:15:23      阅读:406      评论:0      收藏:0      [点我收藏+]

标签:

【题意】

技术分享

 

【题解】

fhq自己写的题解就很清楚啦 (里面有关于神秘的阿米巴同学的介绍哦!很帅的样子,,,

我再来理一下思路

这道题思路应该是很简单很常规的,,但我做题太少辣!

二分一下肯定是必要的, 下面是判断是否可行的问题。

容易想到 要开一个 f 数组 表示 扫到了 第 i 位时 能匹配上多少个字母, 最后答案就是 f[lenth] * 10 >= lenth * 9 啦

f[i] 显然可以 通过 f[j] 转移 (j <= i - 二分出的下限的长度 + 1  且s[j……i]出现在字典里)

下一步要确定的就是 有哪些 j 是出现在字典里的, 也就是 在 S 中 以 i 为后缀的这个字符串 最长有多少出现在字典里。

后缀自动机模板就出来啦 (此处该有音乐: 当(sou)当(sou)当(sou)当(?mi)……

然后会发现 dp 的时候 j 显然是单调的(如果 i - 1 的转移时的下限 为 j , i 的显然不会小于 j , 否则 i - 1 的也可以小于j 了)

所以单调队列优化一下就好了

 

代码非常非常短

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define MAXN 3000005
using namespace std;
int n, m, lenth, cnt, last, q[MAXN], len[MAXN], trans[MAXN][3], fat[MAXN], f[MAXN];
char s[MAXN];
void insert(int x){
    int np = ++ cnt, p = last;
    len[np] = len[last] + 1; last = np;
    for(; !trans[p][x]; p = fat[p])trans[p][x] = np;
    if(!p)fat[np] = 1;
    else{
        int q = trans[p][x];    
        if(len[q] == len[p] + 1)fat[np] = q;
        else{
            int nq = ++ cnt; len[nq] = len[p] + 1;
            memcpy(trans[nq], trans[q], sizeof(trans[q]));
            fat[nq] = fat[q];
            fat[q] = fat[np] = nq;
            for(; trans[p][x] == q; p = fat[p])trans[p][x] = nq;    
        }
    }   
}
bool pd(int limit){
    int bot = 1, top = 0, cur = 1, ll = 0; f[0] = 0;
    for(int i = 1; i <= lenth; i ++){
        f[i] = f[i - 1];
        int c = s[i] - ‘0‘;
        for(; !trans[cur][c]; cur = fat[cur]);
        if(!cur){cur = 1; ll = 0;}
        ll = min(ll, len[cur]) + 1;
        cur = trans[cur][c];
        int p = i - limit;
        if(p >= 0){
            while(bot <= top && q[top] - f[q[top]] > p - f[p]) top --;
            q[++ top] = p;    
        }
        while(bot <= top && q[bot] < i - ll)bot ++;
        if(bot <= top) f[i] = max(f[i], f[q[bot]] + i - q[bot]);
    } return f[lenth] * 10 >= lenth * 9;
}
int main()
{
    scanf("%d%d", &n, &m);
    last = ++ cnt;
    while(m --){
        scanf("%s", s + 1); lenth = strlen(s + 1);
        for(int i = 1; i <= lenth; i ++)insert(s[i] - ‘0‘);
        insert(2);    
    }
    while(n --){
        scanf("%s", s + 1); lenth = strlen(s + 1);
        int l = 1, r = lenth, mid; 
        while(l + 1 < r){
            mid = l + r >> 1;
            if(pd(mid))l = mid;
            else r = mid - 1;    
        }printf("%d\n", pd(r) ? r : l);
    }
    return 0;
}

 

bzoj 2806: [Ctsc2012]Cheat 熟悉的文章

标签:

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

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