某DP题目4
题意
有两个栈分别有n和m个数,每次从任意栈中取出一个数,令k为不同输出序列的总数,其中第i种输出序列的产生方式有ai个,求Σai2。 n <= 500
分析
此题是关于ai2转换。咋一看此题好像很复杂,但巧妙转化ai2之后就变得极其简单。
ai2到底是什么呢?如果单纯把它当做一个值来看待,可能做不出来。ai表示第i种输出序列的产生方式,而ai2就是其产生方式对数。
设F[i][j][a][b]为第一种方案中,第一个栈去了i个数,第二个栈取了j个数,第二种方案中第一个栈取了a个数,第二个栈中取了b个数,两种方案得到相同的输出序列的方案数。
转移只需要枚举两种方案下一个各选什么。
其实i+j = a+b,b的那一维是可以省去的,时间复杂度为O(n3)
程序
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <iostream> 7 8 using namespace std; 9 10 const int MOD = 10000000007; 11 const int maxn = 505; 12 int n, m, a[maxn], b[maxn]; 13 int f[maxn][maxn][maxn]; 14 15 int main() 16 { 17 freopen("a.in", "r", stdin); 18 freopen("a.out", "w", stdout); 19 scanf("%d %d", &n, &m); 20 for (int i = 1; i <= n; ++i) 21 scanf("%d", &a[i]); 22 for (int i = 1; i <= m; ++i) 23 scanf("%d", &b[i]); 24 for (int i = 0; i <= n; ++i) 25 for (int j = 0; j <= m; ++j) 26 for (int k = 0; k <= n; ++k) 27 { 28 if (k > i+j) 29 break ; 30 if (a[i+1] == a[k+1] && i+1 <= n && k+1 <= n) 31 (f[i+1][j][k+1] += f[i][j][k]) %= MOD; 32 if (a[i+1] == b[i+j-k+1] && i+1 <= n && i+j-k+1 <= m) 33 (f[i+1][j][k] += f[i][j][k]) %= MOD; 34 if (b[j+1] == a[k+1] && j+1 <= m && k+1 <= n) 35 (f[i][j+1][k+1] += f[i][j][k]) %= MOD; 36 if (b[j+1] == b[i+j-k+1] && j+1 <= m && i+j-k+1 <= m) 37 (f[i][j+1][k] += f[i][j][k]) %= MOD; 38 } 39 printf("%d\n", f[n][m][n]); 40 return 0; 41 }
Nothing is impossible!