题目大意:给出一列数 S = {s1, s2, s3, ...., sn},求出其非递减子序列的个数,如: S = {1, 2, 3},非递减子序列:{1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}共7个;原题链接
题目解析:由于本题N太大,用DP可能会超时O(N^2),因为是求和可以用树状数组.但s1,s2....sn可能是相同的;或者是之间相差很大,因此需要对数据先进行离散化处理;
错误分析:s不要忘了赋初值;
#include<cstdio>
#include<iostream>
using namespace std;
#include<cstring>
#include<algorithm>
#define MOD 1000000007
#define MAX 100005
typedef __int64 ll;
ll tree[MAX];
int s[MAX],c[MAX];
int n, top;
int lowb(int x)//取二进制最左边的1;
{
return x&(-x);
}
void update(int x,ll val)//对上更新
{
while(x<=n)
{
tree[x]+=val;
if(tree[x]>=MOD)
tree[x]%=MOD;
x+=lowb(x);
}
}
ll getsum(int x)//求前x个数的和
{
ll s=0;//赋初值
while(x>0)
{
s+=tree[x];
if(s>=MOD)
s%=MOD;
x-=lowb(x);
}
return s;
}
int bin(int x)//二分法查找x的下标位子
{
int l=1,h=top;
while(l<=h)
{
int mid=(l+h)>>1;
if(x==c[mid])return mid;
if(x>c[mid])l=mid+1;
else h=mid-1;
}
}
int main()
{
int i;
while(scanf("%d",&n)!=EOF)
{
for(i=1; i<=n; i++)
{
scanf("%d",&s[i]);
c[i]=s[i];
}
sort(c+1,c+n+1);//排序
top=0;
for(i=1; i<=n; i++)
{
if(i==1||c[i]!=c[i-1])//i==1非i=1;相邻数不同则放到数组中;
{
c[++top]=c[i];
tree[top]=0;
}
}
update(1,1);/*先初始1,因为一个数若是比前面的数大,则以它结尾的子集因为它前面数的的和加1;因此后面就不用加一了*/
ll ans=0;
for(i=1; i<=n; i++)
{
int id=bin(s[i]);
ll temp=getsum(id);
ans+=temp;
if(ans>=MOD)ans%=MOD;
update(id,temp);
}
printf("%I64d\n",ans);
}
return 0;
}