【UOJ #149】【NOIP 2015】子串
http://uoj.ac/submission/93769
设$f(i,j,k)$表示用了A的前i个字符,分k段构成B的前j个字符的方案数。
$$f(i,j,k)=f(i-1,j,k)+\sum_l f(i-l,j-l,k-1)$$
$$\sum_l f(i-l,j-l,k-1)=sum(i,j,k)$$
$$sum(i,j,k)=[A(i)=B(j)](sum(i-1,j-1,k)+f(i-1,j-1,k-1))$$
时间复杂度$O(nmk)$
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int p = 1000000007; int in() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = (k << 3) + (k << 1) + c - '0'; return k * fh; } int f[203][203], sum[203][203], la, lb, step; char A[1003], B[203]; int main() { la = in(); lb = in(); step = in(); scanf("%s%s", A + 1, B + 1); f[0][0] = 1; for(int i = 1; i <= la; ++i) for(int j = lb; j >= 1; --j) if (A[i] == B[j]) for(int k = min(step, j); k >= 1; --k) { sum[j][k] = (sum[j - 1][k] + f[j - 1][k - 1]) % p; f[j][k] = (f[j][k] + sum[j][k]) % p; } else memset(sum[j], 0, sizeof(int) * (min(step, j) + 1)); printf("%d\n", f[lb][step]); return 0; }
~
NOI 2017 Bless All