Codeforces Round #422 (Div. 2) E. Liar 贪心 dp 后缀数组

来源:互联网 发布:快递员扫码发短信软件 编辑:程序博客网 时间:2024/06/08 16:25

给两个串,a与b,长度1e5,最多可以在a中选出x段互不相交的连续子串,问能不能拼成b,x的范围最多为30。

解法:

可以想到dp,dp[i][j]表示 a 串前 j 个字符取 i 段,能匹配到 b 串的最大前缀。这个状态是通过贪心构造的。

转移的时候也是贪心转移,分为多一段和不要这个字符两种情况。

a) 多一段:dp[i+1][j+lcp(a[j],b[dp[i][j]])]=max(dp[i+1][j+lcp(a[j],b[dp[i][j]])],dp[i][j]+lcp(a[j],dp[i][j])); 因为如果要从a串的a[j]处, b串的b[dp[i][j]]处取一段相同子串,可以贪心地取最长的一段,其中lcp(a[j],dp[i][j]) 可以拿后缀数组或者哈希维护。

b) 不要当前字符:dp[i][j+1]=max(dp[i][j+1],dp[i][j]);

#include <bits/stdc++.h>using namespace std;const int maxn=200005;string s,t,o;bool flag;int N,K,Rank[maxn],tmp[maxn],sa[maxn],lcp[maxn],n,m,x,st[20][maxn],dp[32][maxn];inline bool compare_sa(int i,int j) {    if (Rank[i]!=Rank[j])        return Rank[i]<Rank[j];    else {        int ri=(i+K<=N)?Rank[i+K]:-1;        int rj=(j+K<=N)?Rank[j+K]:-1;        return ri<rj;    }}inline void construct_sa(string S,int *sa) {    N=S.length();    for (int i=0;i<=N;++i) {        sa[i]=i;        Rank[i]=i<N?S[i]:-1;    }    for (K=1;K<=N;K*=2) {        sort(sa,sa+N+1,compare_sa);        tmp[sa[0]]=0;        for (int i=1;i<=N;++i)            tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);        for (int i=0;i<=N;++i)            Rank[i]=tmp[i];    }}inline void construct_lcp(string S,int *sa,int *lcp) {    N=S.length();    int h=0;    lcp[0]=0;    for (int i=0;i<N;++i) {        int j=sa[Rank[i]-1];        h=max(h-1,0);        for (;j+h<N&&i+h<N;++h)            if (S[j+h]!=S[i+h])                break;        lcp[Rank[i]-1]=h;    }}inline void construct_rmq(int *lcp,int n) {    for (int i=0;i<n;++i)        st[0][i]=lcp[i];    for (int i=1;i<20;++i)        for (int j=0;j+(1<<i)-1<n;++j)            st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);}inline int query_rmq(int i,int j) {    int x=0;    while ((1<<(x+1))<=j-i+1)        ++x;    return min(st[x][i],st[x][j-(1<<x)+1]);}void solve() {    for (int i=0;i<=x;++i)        for (int j=0;j<=n;++j) {            if (dp[i][j]>=m) {                puts("YES");                return;            }            int _lcp=query_rmq(min(Rank[j],Rank[dp[i][j]+n+1]),max(Rank[j],Rank[dp[i][j]+n+1])-1);            dp[i+1][j+_lcp]=max(dp[i+1][j+_lcp],dp[i][j]+_lcp);            dp[i][j+1]=max(dp[i][j+1],dp[i][j]);        }    puts("NO");}int main(){    cin>>n>>s>>m>>t>>x;    o=s+'$'+t;    construct_sa(o,sa);    construct_lcp(o,sa,lcp);    construct_rmq(lcp,o.length()+1);    solve();    return 0;}

阅读全文
1 0