• bzoj2806: [Ctsc2012]Cheat(SAM+DP)


    2806: [Ctsc2012]Cheat

    题目:传送门 


    题解:

       感觉这题考的更多的就是DP啊...

       看完题目的第一反应就是广义SAM...(然而并不会)

       再YY一会儿想起来可以直接将作文库连成一个母串(中间用2隔开)去跑SAM,然后直接把文章当成是子串在自动机上面跑(字符串匹配问题的套路啊)

       考虑DP:设f[i]表示前i个位置的最大匹配长度。那么f[i]=max(f[i],f[j]+i-j);

       直接DP肯定爆炸,再考虑利用SAM来预处理一个match[],match[i]表示当前文章以第i个位置结尾的子串和作文库匹配的最长长度(直接在自动机里面乱跑)

       L满足而分性,直接二分,然后我们会发现对于f[i]有影响的其实只在于[i-match[i],i-L],i-L这个玩意肯定单调递增啊...

       一波单调队列直接搞:对于队头,如果位置在合法区间内,则直接可以找到最优解来更新f[i]

       槽点:一开始被卡精度...%AC_Artist.zig_zag之后又WA了...然后发现自己脑残在check里memset。。。(做了一上午...菜啊),数据真的有点水

        


    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 struct SAM
     8 {
     9     int son[5],fail,dep;
    10     SAM(){memset(son,0,sizeof(son));fail=dep=0;}
    11 }ch[2110000];int a[2110000],match[1110000],root,cnt,last;
    12 int n,m;
    13 char s[1110000],st[1110000];
    14 void add(int k)
    15 {
    16     int x=a[k];
    17     int p=last,np=++cnt;ch[np].dep=ch[p].dep+1;
    18     while(p && ch[p].son[x]==0)ch[p].son[x]=np,p=ch[p].fail;
    19     if(p==0)ch[np].fail=root;
    20     else
    21     {
    22         int q=ch[p].son[x];
    23         if(ch[q].dep==ch[p].dep+1)ch[np].fail=q;
    24         else
    25         {
    26             int nq=++cnt;ch[nq]=ch[q];
    27             ch[nq].dep=ch[p].dep+1;
    28             ch[np].fail=ch[q].fail=nq;
    29             while(p && ch[p].son[x]==q)ch[p].son[x]=nq,p=ch[p].fail;
    30         }
    31     }
    32     last=np;
    33 }
    34 void get_match(int len)
    35 {
    36     int p=root,sum=0;
    37     for(int i=1;i<=len;i++)
    38     {
    39         int x=s[i]-'0';
    40         if(ch[p].son[x]!=0)sum++,p=ch[p].son[x];
    41         else //失配了就跳fail 
    42         {
    43             while(p && ch[p].son[x]==0)p=ch[p].fail;
    44             if(p==0)p=root,sum=0;
    45             else sum=ch[p].dep+1,p=ch[p].son[x];
    46         }
    47         match[i]=sum;
    48     }
    49 }
    50 int f[1110000],list[1110000];
    51 bool check(int L,int len)
    52 {
    53     //if(L==0)return true;
    54     f[0]=0;list[1]=0;
    55     int p,head=1,tail=1;
    56     for(int i=1;i<=len;i++)
    57     {
    58         f[i]=f[i-1];p=i-L;if(p<0)continue;
    59         while(head<=tail && f[p]+i-p>f[list[tail]]+i-list[tail])tail--;list[++tail]=p;
    60         while(head<=tail && list[head]<i-match[i])head++;
    61         if(head<=tail)f[i]=max(f[i],f[list[head]]+i-list[head]);
    62     }
    63     double anss=double(f[len])/double(len);
    64     return anss>=0.8999999999;
    65 }
    66 int main()
    67 {
    68     scanf("%d%d",&n,&m);int la=1;
    69     cnt=0;root=last=++cnt;
    70     for(int i=1;i<=m;i++)
    71     {
    72         scanf("%s",st+1);int len=strlen(st+1);int k=0;
    73         for(int j=la;j<=len+la-1;j++)
    74         {
    75             k++;a[j]=st[k]-'0';
    76             add(j);
    77         }
    78         if(i!=m){la=len+la;a[la]=2;add(la);la++;}
    79     }
    80     while(n--)
    81     {
    82         scanf("%s",s+1);int len=strlen(s+1);
    83         get_match(len);
    84         int l=0,r=len,ans=0;
    85         while(l<=r)
    86         {
    87             int mid=(l+r)/2;
    88             if(check(mid,len))ans=mid,l=mid+1;
    89             else r=mid-1;
    90         }
    91         printf("%d
    ",ans);
    92     }
    93     return 0;
    94 }
  • 相关阅读:
    spoj 3273 Treap
    hdu1074 Doing Homework
    hdu1024 Max Sum Plus Plus
    hdu1081 To the Max
    hdu1016 Prime Ring Problem
    hdu4727 The Number Off of FFF
    【判断二分图】C. Catch
    【01染色法判断二分匹配+匈牙利算法求最大匹配】HDU The Accomodation of Students
    【数轴涂色+并查集路径压缩+加速】C. String Reconstruction
    【数轴染色+并查集路径压缩+加速】数轴染色
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8716143.html
Copyright © 2020-2023  润新知