HDU 4991 Ordered Subsequence(dp+树状数组)

来源:互联网 发布:西班牙域名 编辑:程序博客网 时间:2024/05/14 15:04

好题啊。  自己想的dp。


dp【i】【j】 代表第i个数时  递增长度为 j 的个数。 


明显 d【i】【j】 = sum(d【k】【j-1】 && num【k】 < num【i】)


但是写暴力的话 需要三层循环  n^2*k 的复杂度。 肯定超时。


递推公式有个特点。 到达每一项之后 都是前面项数的和。  所以需要用树状数组优化。(正好是求前缀和)


#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#include <cmath>#include <cstdlib>#include <string>#include <map>#include <vector>#include <set>#include <queue>#include <stack>#include <cctype>using namespace std;typedef long long LL;typedef unsigned long long ULL;#define MAXN 10000+10#define INF (1<<30)#define mod 123456789int c[MAXN];int n,k;int lowbit(int x){    return x & (-x);}void update(int pos,LL val){    while(pos <= n)    {        c[pos] = (c[pos]+ val)%mod;        pos += lowbit(pos);    }}LL Sum(int pos){    LL res = 0;    while(pos > 0)    {        res = (res+c[pos])%mod;        pos -= lowbit(pos);    }    return res;}LL d[MAXN][101];LL a[MAXN];LL b[MAXN];int main (){    while(scanf("%d%d",&n,&k) != EOF){        for(int i = 1; i <= n; i++){            scanf("%I64d",&a[i]);            b[i] = a[i];        }        memset(d,0,sizeof(d));        for(int i = 1; i <= n; i++){            d[i][1] = 1;        }        sort(b+1,b+1+n);        LL ans = 0;        for(int i = 2; i <= k; i++){            memset(c,0,sizeof(c));            for(int j = 1; j <= n; j++){                int id = lower_bound(b+1,b+1+n,a[j]) - (b); //  自己的编号(相当于离散化,因为数据原本很大,这样可以缩小到1-10000)                d[j][i] = Sum(id-1);   // 求 小于 a[j] 的 所有数 长度为 i-1的和。                update(id,d[j][i-1]);  // 把 c 数组的 id位置更新成 d[j][i-1] 以便于 下一个 数字的时候 求和            }        }        LL sum = 0;        for(int j = 1; j <= n; j++){            sum = (sum+d[j][k])%mod;        }        printf("%I64d\n",sum);    }    return 0;}


0 0
原创粉丝点击