hdu 2227 树状数组+dp

来源:互联网 发布:贪吃蛇java代码详解 编辑:程序博客网 时间:2024/05/03 05:07

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

很显然,如果只用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 1000000007struct 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;}




0 0