这场的题都让我收获颇丰啊QWQ 感谢van♂老师
T1 喵喵喵!当时以为经典题只能那么做, 思维定势了...
因为DP本质是通过一些条件和答案互相递推的一个过程, 实际上就是把条件和答案分配在DP的状态和结果中, 所以当条件数值非常大, 而答案比较小的时候, 完全可以将答案放在DP数组的状态中,用来递推条件, 如果这个条件合法, 那么表明这个答案是可行的。
在这题里面, 答案不会超过b串的长度, 而a串的长度可以非常长, 所以可以设f[i][j]为b串中前i个字符, 匹配了j为在a串中的最前位置是什么, 用序列自动机处理出nxt[i][x]为a串第i位的下一个x字符的位置,就很好转移了。
#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; }