Find the nondecreasing subsequences
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1564 Accepted Submission(s): 563
Problem Description
How many nondecreasing subsequences can you find in the sequence S = {s1, s2, s3, ...., sn} ? For example, we assume that S = {1, 2, 3}, and you can find seven nondecreasing subsequences, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}.
Input
The input consists of multiple test cases. Each case begins with a line containing a positive integer n that is the length of the sequence S, the next line contains n integers {s1, s2, s3, ...., sn}, 1 <= n <= 100000, 0 <= si <= 2^31.
Output
For each test case, output one line containing the number of nondecreasing subsequences you can find from the sequence S, the answer should % 1000000007.
Sample Input
Sample Output
Author
8600
Recommend
lcy
题目描述 :求一段序列的上海上升序列的个数 dp[i]= sum(dp[j]+1) &&(a[j]<a[i])
因为a[j]<a[i] ,所以相当于求正序数的个数
求逆序数一般有三种解法 1 暴力 2 归并排序 3 树状数组
树状数组求法 :
原始序列为 5 4 1 2 3
int answer=0;
一 在1的位置上加一 answer+=sum(i-1); answer=0;
0 0 1 0 0
二在2的位置上加一 answer+=sum(3); answer=1;
0 0 1 1 0
三在3的位置上加一 answer+=sum(4); answer=3
0 0 1 1 1
四 在四的位置上加一 answer+=sum(1);answer=3;
0 1 1 1 1
五 在五的位置上加一 answer+=sum(0);answr=3;
1 1 1 1 1
此题要求所有的上升序列的个数,有了递推式应该很好求,
可是我陷入了一个误区 ,认为既然是递推式,那么就应该按照天然的顺序,逐个递推(因为计算当前状态值需要用到前面所有的状态值),
可是要求正序数的话需要从小到大,逐个放入,计算前面的数之和,瞬间就无语了,怎么办呢?观察递推式 dp[i]= sum(dp[j]+1) &&(a[j]<a[i])
如果从小到大放的话,假设放i位置,那么i之前的就是比它小的已经放过的,没有放的就是对i状态的值无影响的,先放还是后放对i
状态没有影响,这样我们就可以去掉对i来说的冗余信息,相当于只对 a[j] < a[i] 的 j 进行递推,
我们设 A[i]代表以i结尾的上升序列的个数,A[i]=sum(i-1)+1;sum(i-1)代表之前所有的上升序列的个数,sum(i-1) == A[1]+A[2]+A[3]+.....+A[i-1];
假设从小到大进行求解,利用暴力求和,时间复杂度太高,
那么我们利用树状数组进行点(A[i])修改和查询操作,时间复杂度降为 long(N);
也可利用线段树进行点修改和查询操作
采用树状数组,从小到大 ,放入 它自己的位置,然后更新A[i],那么答案就是sum(N);
假设原始序列为 5 4 1 2 3
一
0 0 0 0 0
二
0 0 1 0 0
三
0 0 1 2 0
四
0 0 1 2 4
五
0 1 1 2 4
六
1 1 1 2 4
那么答案就是1 + 1 + 1 + 2 + 4=9,利用树状数组进行求和
#include <iostream>
#include <cstdio>
#include <time.h>
#include <stdlib.h>
#include <cstring>
#include<algorithm>
#define M 100100
#define MOD 1000000007
#define LL long long
using namespace std;
struct node
{
LL value,id;
};
bool cmp (node a,node b)
{
if(a.value!=b.value)
return a.value<b.value;
else
return a.id<b.id;
}
node a[M];
LL dp[M];
LL c[M];
LL N;
void init()
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
memset(c,0,sizeof(c));
}
//树状数组
LL lowbit(LL x)
{
return x&(-x);
}
LL sum(LL x)
{
LL ret=0;
while(x>0)
{
ret=ret%MOD;
ret+=c[x];
x-=lowbit(x);
}
return ret%MOD;
}
void add(LL x,LL extra)
{
while(x <= N)
{
c[x]=c[x]%MOD;
c[x]=c[x]+1+extra; //A[i]加上i之前的所有的上升序列的个数 A[i]=sum(i-1)+1;sum(i-1)代表之前所有的上升序列的个数
x+=lowbit(x);
}
}
LL solve()
{
add(a[1].id,0);
// answer+=sum(a[1].id);
//printf("%lld\n",sum(a[1].id));
for(int i=2;i<=N;i++)
{
add(a[i].id,sum(a[i].id-1)); //A[i]加上i之前的所有的上升序列的个数 A[i]=sum(i-1)+1;sum(i-1)代表之前所有的上升序列的个数
// answer=answer % MOD;
// answer+=sum(a[i].id);
// printf("%lld\n",sum(a[i].id));
}
return sum(N) % MOD;
}
int main()
{
while(~scanf("%d",&N))
{
init();
for(int i=1;i<=N;i++)
{
scanf("%I64d",&a[i].value);
a[i].id=i;
//printf("%I64d %I64d\n",a[i].value,a[i].id);
}
/*for(int i=1;i<=N;i++)
{
printf("%lld %lld\n",a[i].value,a[i].id);
}*/
sort(a+1,a+N+1,cmp);
printf("%I64d\n",solve());
}
return 0;
}
hdu 2227
原文:http://www.cnblogs.com/xianbin7/p/4471772.html