1. 程式人生 > >HDU 5542 The Battle of Chibi dp+樹狀數組

HDU 5542 The Battle of Chibi dp+樹狀數組

mod sizeof tac pro sum cpp case name problem

題目:http://acm.hdu.edu.cn/showproblem.php?pid=5542

題意:給你n個數,求其中上升子序列長度為m的個數

可以考慮用dp[i][j]表示以a[i]結尾的長度為j的上升子序列有多少

裸的dp是o(n2m) 所以需要優化

我們可以發現dp的第3維是找比它小的數,那麽就可以用樹狀數組來找

這樣就可以降低復雜度

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
const int mod=1e9+7;
int n,m;
int a[1005];
int b[1005];
int dp[1005][1005];
int sum(int x,int y)
{
    int ans=0;
    while(x)
    {
        ans=(ans+dp[x][y])%mod;
        x-=x&-x;
    }
    return ans;
}
void add(int x,int y,int val)
{
    while(x<=n)
    {
        dp[x][y]=(dp[x][y]+val)%mod;
        x+=x&-x;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+1+n);
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(b+1,b+1+n,a[i])-b;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            int t=min(i,m);
            for(int j=1;j<=t;j++)
            {
                if (j==1) add(a[i],1,1);
                else
                {
                    int t=sum(a[i]-1,j-1);
                    add(a[i],j,t);
                }
            }
        }
        printf("Case #%d: %d\n",ca,sum(n,m));
    }
    return 0;
}

  

HDU 5542 The Battle of Chibi dp+樹狀數組