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

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

【题意】

  • 给定长为n的序列,问有多少个长为m的严格上升子序列?

【思路】

  • dp[i][j]表示以a[i]结尾的长度为j的严格上升子序列有多少个
  • dp[i][j]=sum{dp[k][j-1]},k小于i且a[k]<a[i]
  • 区间dp,复杂度为O(n^3)
  • 会超时,第三层循环求和用树状数组加速
  • 时间复杂度为O(n^2logn)
  • 离散化的时候排序后不去重(否则WA)

【Accepted】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>

using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e3+3;
ll a[maxn];
ll b[maxn];
ll dp[maxn][maxn];
int cnt;
int n,m;
int lowbit(int x)
{
    return x&(-x);
}

ll add(int x,int y,ll d)
{
    while(x<=n)
    {
        dp[x][y]=(dp[x][y]+d)%mod;
        x+=lowbit(x);
    }
}

ll sum(int x,int y)
{
    ll res=0ll;
    while(x)
    {
        res=(res+dp[x][y])%mod;
        x-=lowbit(x);
    }
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    int cas=0;
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);                
        }    
        memcpy(b,a,sizeof(b));
        sort(a+1,a+n+1);
        //cnt=unique(a+1,a+n+1)-a-1;
        for(int i=1;i<=n;i++)
        {
            int pos=lower_bound(a+1,a+n+1,b[i])-a;
            for(int j=1;j<=min(i+1,m);j++)
            {
                ll tmp;
                if(j==1) tmp=1ll; 
                else tmp=sum(pos-1,j-1);
                add(pos,j,tmp);
            }
        }
        ll ans=sum(n,m);
        printf("Case #%d: %d\n",++cas,(int)ans);    
    }
    return 0;
}
View Code

 【疑问】

为啥不可以去重?

posted @ 2017-07-26 19:28  shulin15  阅读(338)  评论(0编辑  收藏  举报