poj 3378 Crazy Thairs 动态规划

来源:互联网 发布:中国女性数据库 编辑:程序博客网 时间:2024/06/05 11:24

题目链接:http://poj.org/problem?id=3378

 

题目大意:

      找出原序列中满足:

1. 1 ≤ i < j < k < l < m ≤ N
2. Ai < Aj < Ak < Al < Am

      两个条件长度为5的子序列个数。

 

题目分析:

      长度为5,我们可以从长度为1开始推算,一直推到长度为5。

      首先,对于长度为1的,所有的数都满足条件。对于长度为2的,我们就可以这样算了:在ai出现之前,有多少个小于ai的数,就有多少以ai结束且长度为2的序列满足条件。同理,对于长度为3的,可以求出在ai之前满足(长度为2且ak<ai)条件的有多少,便可知以ai结尾的长度为3的有多少个;以此类推……

      在求ai之前小于ai的数时,可以用数状数组来优化。具体过程是:在求dp[i][j]时,dp[i][j] = sum(dp[i-1][k]); (1<=k<j && ak < ai),即在求和时用树状数组,在求完dp[i][j]后更新树状数组:update(aj, dp[i-1][j]),因为在dp[i][j]里记录的就是长度为i以j结束的序列有多少个。

      最后需要注意就是要用高精度了。

 

代码实现:

#include <stdio.h>#include <string.h>#include <stdlib.h>#define maxn 50005#define M 100000000typedef struct{int a, b, c;}bint;int a[maxn], h[maxn], n, len;bint dp[6][maxn], c[maxn];int cmp(const void* x, const void* y) {return *(int*)x - *(int*)y;}inline int bs(int v) {int* p = (int*)bsearch(&v, h + 1, len + 1, sizeof(int), cmp);return p - h;}inline bint add(bint a, bint b) {a.a += b.a; a.b += b.b; a.c += b.c;a.b += a.c / M; a.a += a.b / M;a.b %= M; a.c %= M;return a;}inline void print(bint a) {if (a.a) {printf("%d%08d%08d\n", a.a, a.b, a.c);} else if (a.b) {printf("%d%08d\n", a.b, a.c);} else {printf("%d\n", a.c);}}// 更新树状数组inline void update(int t, bint v) {while (t <= n) {c[t] = add(c[t], v);t += t & -t;}}// 树状数组求和inline bint sum(int t) {bint s = {0, 0, 0};while (t) {s = add(s, c[t]);t -= t & -t;}return s;}int main() {while (scanf("%d", &n) != EOF) {for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);h[i] = a[i];}// 离散化qsort(h + 1, n, sizeof(int), cmp);len = 1;for (int i = 2; i <= n; i++)if (h[i] != h[len])h[++len] = h[i];for (int i = 1; i <= n; i++)a[i] = bs(a[i]);// 对dp[1][i]进行初始化memset(dp, 0, sizeof(dp));for (int i = 1; i <= n; i++)dp[1][i].c = 1;for (int i = 2; i <= 5; i++) {// 对树状数组c复用,每次归0memset(c, 0, sizeof(c));for (int j = i - 1; j <= n; j++) {dp[i][j] = sum(a[j] - 1); // 先求出dp[i][j]update(a[j], dp[i - 1][j]); // 再更新c}}// dp[5][]里的结果之和就是最后结果bint res = {0, 0, 0};for (int i = 5; i <= n; i++)res = add(res, dp[5][i]);print(res);}return 0;}