hdu 2227 树状数组+dp

题意是求一个数列的不递减的子序列的个数;

很显然,如果只用dp来做的话时间是O(n*n) 因为dp【i】为前i个数可能的方案,则状态转移方程为dp【i】=sum(dp【j】,j<i&&num【j】<=num【i】)+1 对小数据坑定能过 但大数据就超时了,这里用到了树状数组来优化;

先对num按数来进行排序,(这道题因为数据较大  用到了离散化) 因为更新是是按原序更新的,及i之前的num【j】一定比num【i】小,维护了不递减的原则,更新是从mark【i】(表示原序列i在排序后的位置)开始更新 这就维护了子序列的原则,最后求和就行;

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

#define mod 1000000007

struct node
{
    int value;
    int ii;
}num[100010];
int cmp(node a,node b)
{
    return a.value<b.value;
}
int cont[100010],n;
int update(int a,int b)
{
    for(int i=a;i<=n;i+=(i&-i))
    {
        cont[i]+=b;
        cont[i]%=mod;
    }    
    return 0;
}
int find(int a)
{
    int s=0;
    for(int i=a;i>=1;i-=(i&-i))
    {
        s+=cont[i];
        s%=mod;
    }    
    return s;
}
int main()
{
    int i,j;
    int mark[100010];
    int dp[100010];
    while(~scanf("%d",&n))
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num[i].value);
            num[i].ii=i;
        }
        sort(num+1,num+1+n,cmp);
        int k=-1,t=0;
        for(i=1;i<=n;i++)
        {
            if(num[i].value!=k)
            {
                ++t;
                k=num[i].value;
            }
            mark[num[i].ii]=t;
        }
        memset(cont,0,sizeof(cont));
        for(i=1;i<=n;i++)
        {
            dp[i]=find(mark[i]);
            dp[i]%=mod;
            update(mark[i],dp[i]+1);
        }
        printf("%d\n",find(n));
    }
    return 0;
}




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。