CF176DHyper String题解

考虑dp状态

dp[pre][len]考虑到s的前缀为pre,其与t的最大公共子序列为len的最小前缀 

考虑转移

dp[pre][len]=min(dp[pre-1][len],在dp[pre-1][len-1]右面最靠左的和s[pre]相同的位置)

为了o(1)转移考虑预处理两个数组

dp1[i][j][k]表示在b[i]字符串上的第j个位置右面最靠左的字符为k的位置

dp2[i][k]表示在t[i]右面含有字符k的最靠左的位置

然后就可以ac这道题了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<algorithm>
#define er -'a'+1
#define inf 0x3f3f3f3f
#define maxn 2010
using namespace std;
namespace lin
{
    string s;
    string t[maxn];
    struct linlin
    {
        int lin[30];
    };
    struct jialin
    {
        int num,id;
        jialin(){}
        jialin(int _num,int _id){
            num=_num,id=_id;
        }
        friend bool operator < (jialin xx,jialin yy)
        {
            return xx.num>yy.num;
        }
    };
    set<jialin>st;
    set<jialin>::iterator it;
    vector<linlin> dp1[maxn];
    int wjll[maxn][30];
    int dp2[maxn][30];
    int dp[maxn][maxn];//dp[pre][len]考虑到s的前缀为pre,其与t的最大公共子序列为len的最小前缀 
    int vist[40];
    int vis[30];
    int a[maxn],sum[maxn];
    int query(int x,int op)
    {
        if(x==inf) return inf;
        it=st.lower_bound(jialin(x,20060913));
        jialin tmp=*it;
        int tt=tmp.id;
        if(sum[tt]==x)
            tt--;
        int sw=x-sum[tt<0?0:tt];
        if(sw>0)
            if(dp1[a[tt+1]][sw-1].lin[op])
            {
                return sum[tt]+dp1[a[tt+1]][sw-1].lin[op];
            }
        tt=dp2[tt+1][op];
        if((int)(t[a[tt]][0] er)==op)
            return sum[tt-1]+1;
        if(dp1[a[tt]][0].lin[op])
        {
            return sum[tt-1]+dp1[a[tt]][0].lin[op];
        }
        return inf;
    }
    int love(int wjl)
    {
        int n,m;
        ios::sync_with_stdio(false);
        cin.tie(NULL);
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>t[i];
            int siz=t[i].size();
            for(int j=0;j<siz;j++)
                wjll[i][t[i][j] er]=1;
        }
        cin>>m;
        st.insert(jialin(0,0));
        for(int i=1;i<=m;i++)
        {
            cin>>a[i];
            sum[i]=sum[i-1]+(int)t[a[i]].size();
            st.insert(jialin(sum[i],i));
        }
        for(int i=m;i>=0;i--)
        {
            for(int j=1;j<=26;j++)
                dp2[i][j]=vist[j];
            for(int j=1;j<=26;j++)
                if(wjll[a[i]][j])
                    vist[j]=i;
        }
        for(int i=1;i<=n;i++)
        {
            int siz=t[i].size();
            memset(vis,0,sizeof(vis));
            for(int j=siz-1;j>=0;j--)
            {
                linlin tmp;
                for(int z=1;z<=26;z++)
                    tmp.lin[z]=vis[z];
                dp1[i].push_back(tmp);
                vis[t[i][j] er]=j+1;
            }
            reverse(dp1[i].begin(),dp1[i].end());
        }
        cin>>s;
        int nn=s.size();
        memset(dp,0x3f,sizeof(dp));
        dp[0][0]=0; 
        linlin tmp;
        memset(tmp.lin,0,sizeof(tmp.lin)); 
        dp1[0].push_back(tmp);
        for(int i=1;i<=nn;i++)
        {
            for(int j=0;j<=nn;j++)
            {
                if(i==3&&j==3)
                    i++,i--;
                dp[i][j]=dp[i-1][j];
                if(j!=0)
                    dp[i][j]=min(dp[i][j],query(dp[i-1][j-1],s[i-1] er));
            }
        }
        for(int i=nn;i>=0;i--)
        {
            if(dp[nn][i]!=inf)
            {
                cout<<i;
                return wjl;
            }
        }
        return wjl;
    }
}
signed main()
{
    return lin::love(0);
}

 

posted @ 2022-08-12 14:33  lntyh  阅读(35)  评论(0)    收藏  举报