bzoj 2806: [Ctsc2012]Cheat

題目大意:

這題就是sam,再二分加上單調隊列優化DP。。。

就是先用標準作文庫先做一個sam,中間用2隔開就行了

然後對於每個串,就先放到sam裏去匹配,找到最長可以匹配的長度v[i]

二分L,再dp, f[i]=max(f[k]-k)+i  i-v[i]<=k<=i-L  因爲i-v[i]與i-L都是單增的,所以可以用單調隊列優化,最後判斷是否f[n]是否大於等於n*0.9就行了


#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const int maxn=1100011;
int m,n;
void init(){scanf("%*d%d",&m);}
int v[maxn];
bool check(int limit){
    static int q[maxn],head,tail,f[maxn];
    q[head=1]=tail=0; f[0]=0;
    for (int i=1,tmp;i<=n;++i){
        f[i]=f[i-1];
        if ((tmp=i-limit)>=0){
            while (head<=tail && f[tmp]-tmp>=f[q[tail]]-q[tail]) --tail;
            q[++tail]=tmp;
        }
        while (head<=tail && i-v[i]>q[head]) ++head;
        if (head<=tail) f[i]=max(f[i],f[q[head]]+i-q[head]);
    }
    return f[n]>=n*0.9-eps;
}
struct Tsam{
    struct Tnode{
        Tnode *ch[3],*f; int ml;
        void clear(){memset(ch,0,sizeof(0)); f=NULL; ml=0;}
    }e[maxn<<1],*root,*last;
    int tot;
    Tnode *newnode(){e[tot].clear(); return e+(tot++);}
    void clear(){tot=0; root=last=newnode();}
    void add(int c){
        Tnode *np=newnode(),*p=last; np->ml=p->ml+1;
        for (last=np;p && !p->ch[c];p=p->f) p->ch[c]=np;
        if (!p) return np->f=root,void();
        Tnode *q=p->ch[c];
        if (q->ml==p->ml+1) return np->f=q,void();
        Tnode *r=newnode(); *r=*q; r->ml=p->ml+1;
        for (q->f=np->f=r;p && p->ch[c]==q;p=p->f) p->ch[c]=r;
    }
}sam;
char s[maxn];
void work(){
    for (sam.clear();m;m--){
        sam.add(2); scanf("%s",s);
        for (int i=0;s[i];++i) sam.add(s[i]-'0'); 
    }
    while (scanf("%s",s+1)!=EOF){
        n=strlen(s+1); Tsam::Tnode *p=sam.root;
        for (int i=1,len=0,c;i<=n;++i){
            c=s[i]-'0';
            if (p->ch[c]) p=p->ch[c],++len;
            else{
                while (p && !p->ch[c]) p=p->f;
                if (!p) p=sam.root,len=0;
                else len=p->ml+1,p=p->ch[c];
            }
            v[i]=len;
        }
        int t=1,w=n,mid;
        while (t<=w){
            mid=(t+w)>>1;
            if (check(mid)) t=mid+1;
            else w=mid-1;
        }
        printf("%d\n",t-1);
    }
}
int main(){
    init();
    work();
    return 0;
}
切過一道CTSC的題就是爽啊,果然還是太弱了。。。
發佈了43 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章