解题:HEOI 2015 最短不公共子串

题面

制杖四合一,HEOI以前居然出这种**题,看来HE还是联考比较好= =

首先对第二个串建SAM

第一个简单,以每个位置为起点在SAM上走,失配时更新答案

第二个先在第二个串上预处理$firs[i][j]$每个字母在位置$i$后最早在$j$出现,然后在第一个串里$n^2$枚举在$firs$上走,失配时更新答案(这是不是就是序列自动机啊=。=

第三个设个$dp[i][j]$表示考虑前$i$个状态为$j$的答案,然后和第一个一样

第四个$dp[i][j]$第二维改为表示第$j$个,然后和第二个一样

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=2005,M=4005;
  6 char a[N],b[N];
  7 int l1,l2,tot,lst;
  8 int firs[N][26],dp[N][M];
  9 int fth[M],trs[M][26],len[M];
 10 void Insert(int ch) 
 11 {
 12     int newn=++tot,nde=lst; 
 13     lst=newn,len[newn]=len[nde]+1;
 14     while(nde&&!trs[nde][ch])
 15         trs[nde][ch]=newn,nde=fth[nde];
 16     if(!nde)
 17         fth[newn]=1;
 18     else
 19     {
 20         int tran=trs[nde][ch];
 21         if(len[tran]==len[nde]+1)
 22             fth[newn]=tran;
 23         else
 24         {
 25             int rnde=++tot; len[rnde]=len[nde]+1;
 26             for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i];
 27             fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde;
 28             while(nde&&trs[nde][ch]==tran)
 29                 trs[nde][ch]=rnde,nde=fth[nde];
 30         }
 31     }
 32 }
 33 void Solve(int typ)
 34 {
 35     int ans=l1;
 36     if(typ==1)
 37     {
 38         for(int i=1;i<=l1;i++)
 39         {
 40             int nde=1;
 41             for(int j=i;j<=l1;j++)
 42             {
 43                 nde=trs[nde][(int)a[j]];
 44                 if(!nde) {ans=min(ans,j-i+1); break;}
 45             }
 46         }
 47     }
 48     if(typ==3)
 49     {
 50         for(int i=0;i<=l1;i++)
 51             for(int j=0;j<=tot;j++)
 52                 dp[i][j]=l1; dp[0][1]=0;
 53         for(int i=1;i<=l1;i++)
 54             for(int j=1;j<=tot;j++)
 55             {
 56                 dp[i][j]=min(dp[i][j],dp[i-1][j]);
 57                 int tran=trs[j][(int)a[i]];
 58                 if(!tran) ans=min(ans,dp[i-1][j]+1);
 59                 else dp[i][tran]=min(dp[i][tran],dp[i-1][j]+1);
 60             }
 61     }
 62     if(typ==2)
 63     {
 64         for(int i=0;i<=25;i++) firs[l2][i]=l2+1;
 65         for(int i=l2-1;~i;i--)
 66             for(int j=0;j<=25;j++)
 67                 firs[i][j]=(b[i+1]==j)?i+1:firs[i+1][j];
 68         for(int i=1;i<=l1;i++)
 69         {
 70             int pos=0;
 71             for(int j=i;j<=l1;j++)
 72             {
 73                 pos=firs[pos][(int)a[j]];
 74                 if(pos>l2) {ans=min(ans,j-i+1); break;}
 75             }
 76         }
 77     }
 78     if(typ==4)
 79     {
 80         for(int i=0;i<=l1;i++)
 81             for(int j=0;j<=l2;j++)
 82                 dp[i][j]=l1; dp[0][0]=0;
 83         for(int i=1;i<=l1;i++)
 84             for(int j=0;j<=l2;j++)
 85             {
 86                 dp[i][j]=min(dp[i][j],dp[i-1][j]);
 87                 int fir=firs[j][(int)a[i]];
 88                 if(fir>l2) ans=min(ans,dp[i-1][j]+1);
 89                 else dp[i][fir]=min(dp[i][fir],dp[i-1][j]+1);
 90             }
 91     }
 92     printf("%d
",ans);
 93 }
 94 int main()
 95 {
 96     scanf("%s%s",a+1,b+1);
 97     l1=strlen(a+1),l2=strlen(b+1),tot=lst=1;
 98     for(int i=1;i<=l1;i++) a[i]-='a';
 99     for(int i=1;i<=l2;i++) b[i]-='a';
100     for(int i=1;i<=l2;i++) Insert(b[i]);
101     for(int i=1;i<=4;i++) Solve(i);
102     return 0;
103 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/10251977.html