[NOIP2015]子串
刚开始我以为是kmp+dp,后来发现其实没那么复杂。
令dp[i][j][h][0/1]表示A串到第 i 位,B串到第 j 位,其中A串取了k个子串时,Ai 取/不取的方案数。那么转移方程就很容易的写出来了:
dp[i][j][h][0] = dp[i - 1][j][h][0] + dp[i - 1][j][h][1]
dp[i][j][h][1] = dp[i - 1][j - 1][h][1] + dp[i - 1][j - 1][h - 1][1] + dp[i - 1][j - 1][h - 1][0] (a[i] == b[j])
初始化dp[i][0][0][0] = 1. (0 <= i <= n) (我就因为dp[0][0][0][0]没初始化debug了好半天!)
然后用滚动数组把第一位优化掉,就A了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const ll mod = 1e9 + 7; 21 const int maxn = 1e3 + 5; 22 const int maxm = 205; 23 inline ll read() 24 { 25 ll ans = 0; 26 char ch = getchar(), last = ' '; 27 while(!isdigit(ch)) {last = ch; ch = getchar();} 28 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 29 if(last == '-') ans = -ans; 30 return ans; 31 } 32 inline void write(ll x) 33 { 34 if(x < 0) x = -x, putchar('-'); 35 if(x >= 10) write(x / 10); 36 putchar(x % 10 + '0'); 37 } 38 39 int n, m, k; 40 char a[maxn], b[maxm]; 41 ll dp[2][maxm][maxm][2]; 42 43 int main() 44 { 45 n = read(); m = read(); k = read(); 46 scanf("%s%s", a + 1, b + 1); 47 int o = 0; 48 for(int i = 1; i <= n; ++i, o ^= 1) 49 { 50 dp[o ^ 1][0][0][0] = 1; 51 for(int j = 1; j <= min(i, m); ++j) 52 for(int h = 1; h <= min(j, k); ++h) 53 { 54 dp[o][j][h][0] = dp[o][j][h][1] = 0; 55 dp[o][j][h][0] = (dp[o ^ 1][j][h][0] + dp[o ^ 1][j][h][1]) % mod; 56 if(a[i] == b[j]) 57 { 58 dp[o][j][h][1] = (dp[o ^ 1][j - 1][h][1] + dp[o ^ 1][j - 1][h - 1][1]) % mod; 59 dp[o][j][h][1] = (dp[o][j][h][1] + dp[o ^ 1][j - 1][h - 1][0]) % mod; 60 } 61 } 62 } 63 write((dp[o ^ 1][m][k][0] + dp[o ^ 1][m][k][1]) % mod), enter; 64 return 0; 65 }