题意是求一个数列的不递减的子序列的个数;
很显然,如果只用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; }
时间: 2024-10-24 22:04:36