这场的题都让我收获颇丰啊QWQ 感谢van♂老师

  T1 喵喵喵!当时以为经典题只能那么做, 思维定势了...

  因为DP本质是通过一些条件和答案互相递推的一个过程, 实际上就是把条件和答案分配在DP的状态和结果中, 所以当条件数值非常大, 而答案比较小的时候, 完全可以将答案放在DP数组的状态中,用来递推条件, 如果这个条件合法, 那么表明这个答案是可行的。

  在这题里面, 答案不会超过b串的长度, 而a串的长度可以非常长, 所以可以设f[i][j]为b串中前i个字符, 匹配了j为在a串中的最前位置是什么, 用序列自动机处理出nxt[i][x]为a串第i位的下一个x字符的位置,就很好转移了。

浴谷八连测R6题解(收获颇丰.jpg)

浴谷八连测R6题解(收获颇丰.jpg)

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio> 
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn=1010,inf=1e9;
int n1, n2, ans;
int f[maxn][maxn], last[26], nxt[1000010][26];
char s1[1000010], s2[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
inline int max(int a, int b){return a>b?a:b;}
inline int min(int a, int b){return a<b?a:b;}
int main()
{
    scanf("%s", s1+1); scanf("%s", s2+1);
    int n1=strlen(s1+1), n2=strlen(s2+1);
    memset(f,32,sizeof(f)); f[0][0]=0;
    for(int i=0;i<26;i++) last[i]=inf;
    for(int i=n1;i>=0;i--) 
    {
        for(int j=0;j<26;j++) nxt[i][j]=last[j];
        if(i) last[s1[i]-'a']=i;
    }
    for(int i=0;i<=n2;i++)
        for(int j=0;j<=i;j++)
        if(f[i][j]<=n1)
        {
            f[i+1][j]=min(f[i+1][j], f[i][j]);
            f[i+1][j+1]=min(f[i+1][j+1], nxt[f[i][j]][s2[i+1]-'a']);
            ans=max(ans, j);
        }
    printf("%d\n", ans);
    return 0;
}
View Code

相关文章: