某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 }

 

posted @ 2017-02-22 10:18  Splay  阅读(218)  评论(0编辑  收藏  举报