南阳ccpc C题 The Battle of Chibi && hdu5542 The Battle of Chibi (树状数组优化+dp)

题意:

给你一个长度为n的数组,你需要从中找一个长度为m的严格上升子序列

问你最多能找到多少个

 

题解:

我们先对原序列从小到大排序,排序之后的序列就是一个上升序列

这里如果两个数相等的话,那么因为题目要我们求严格上升子序列,所以我们让这个数在数组中原来位置靠后的排序之后让它靠前(靠前也就是下标小)

 

我们dp方程:dp[i][j]表示截至到第i(这个i是按照没排序之前的下标)个元素,上升子序列长度为j的子序列能找到dp[i][j]个

dp转移方程:dp[i][j]=dp[1--i-1][j-1]

dp[1--i-1][j-1]就表示dp[1][j-1]+dp[2][j-1]+...+dp[i-1][j-1]

 

可以说就是求前缀和,这里用的是树状数组维护的

比如原序列为:3 11 5 2 6

排序后序列为:2 3 5 6 11

 

按照排序后这个顺序进行dp,当dp到11的时候,是dp[2][j]的值改变,序列中3,5,6的dp[i][j]中的i大于2,所以不会多求或者少求

而对于dp到6这个数,因为3,5,2这三个数在原序列中的位置就比它靠前,所以轮到求dp[5][j]的时候,2,3,5的dp值都已经求出来了

那么这个时候求出来的前缀和dp[1--4][j]就是正确的

 

这个自己可以模拟看下

 

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<cstring>
using namespace std;
const int mod=1e9+7;
const int maxn=1e3+5;
#define mem(a) memset(a,0,sizeof(a))
//求sum(dp[1-x][j])
int n,m,dp[maxn][maxn];
struct shudui
{
    int id,val;
}que[maxn];
bool cmp(shudui x,shudui y)
{
    if(x.val!=y.val)
        return x.val<y.val;
    return x.id>y.id; //如果两个val相等,因为题目要求严格递增,所以这样排序就可以满足题意
}
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int y,int val)  //更新包含dp[x][y]的
{   //后缀数组项
    while(x<=n)
    {
        dp[x][y]=(dp[x][y]+val)%mod;
        x+=lowbit(x);
    }
}
int get_sum(int x,int y)
{
    int sum=0;
    while(x>0)
    {
        sum=(sum+dp[x][y])%mod;
        x-=lowbit(x);
    }
    return sum;
}
int main()
{
    int t,p=0;
    scanf("%d",&t);
    while(t--)
    {
        mem(dp);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&que[i].val);
            que[i].id=i;
        }
        sort(que+1,que+1+n,cmp);
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=m;++j)
            {
                if(j==1)
                    update(que[i].id,j,1);
                else //因为我们按照val排过序了,所以我们可以加上前缀和就行
                {
                    int sum=get_sum(que[i].id-1,j-1);
                    update(que[i].id,j,sum);
                }
            }
        }
        printf("Case #%d: %d\n",++p,get_sum(n,m));
    }
    return 0;
}

 

posted @ 2020-09-12 19:33  kongbursi  阅读(117)  评论(0编辑  收藏  举报