HDU 5542 The Battle of Chibi dp+树状数组

时间:2022-04-24 19:27:30

题目: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;
}