Find the nondecreasing subsequencesTime Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1215 Accepted Submission(s): 422
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嘛:令F[i](0<=i<=N-1)为以A[i]结尾的不上升子序列的个数。
那么状态转移方程就是F[i]=∑F[j]+1(j<i&&A[j]<A[i]),而最后的答案就是∑F[i](0<=i<=N-1)。
直接DP的话O(N^2)的时间复杂度啊。。。
注意到状态转移方程中的主要问题是:对每个A[i]计算位于A[i]之前且小于A[i]的元素对应的F值之和。
有没有发现这和逆序数的问题很相似?对每个A[i]计算位于A[i]之前且大于A[i]的元素个数。
还不懂怎么搞的话请参见POJ2299:Ultra-QuickSort用线段树(树状数组)求解逆序数的思路。
=======================================代码=======================================
一、线段树。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LSON(N) ((N)<<1 )
#define RSON(N) ((N)<<1|1)
#define MID(A,B) (((A)+(B))>>1)
const int MOD=1000000007;
const int MAXN=100005;
int N,Ans,Orig[MAXN],Sorted[MAXN],SegmTree[MAXN<<2];
int BinSearch(int Goal)
{
int L=0,R=N-1;
while(L<=R)
{
int M=MID(L,R);
if(Sorted[M]==Goal) { return M; }
if(Sorted[M]<Goal) { L=M+1; }
if(Sorted[M]>Goal) { R=M-1; }
}
}
void Insert(int InsID,int InsVal,int L,int R,int N)
{
SegmTree[N]=(SegmTree[N]+InsVal)%MOD;
if(L!=R)
{
int M=MID(L,R);
if(InsID<=M) { Insert(InsID,InsVal,L,M,LSON(N)); }
else { Insert(InsID,InsVal,M+1,R,RSON(N)); }
}
}
int Query(int QueID,int L,int R,int N)
{
if(QueID<L) { return 0; }
if(R<=QueID) { return SegmTree[N]; }
int M=MID(L,R);
return (Query(QueID,L,M,LSON(N))+Query(QueID,M+1,R,RSON(N)))%MOD;
}
int main()
{
while(scanf("%d",&N)==1)
{
Ans=0;
memset(SegmTree,0,sizeof(SegmTree));
for(int i=0;i<N;++i)
{
scanf("%d",&Orig[i]);
Sorted[i]=Orig[i];
}
sort(Sorted,Sorted+N);
for(int i=0;i<N;++i)
{
int index=BinSearch(Orig[i]);
int sum=Query(index,0,N-1,1)+1;
Ans=(Ans+sum)%MOD;
Insert(index,sum,0,N-1,1);
}
printf("%d\n",Ans);
}
return 0;
}
二、树状数组。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MID(A,B) (((A)+(B))>>1)
#define LOWBIT(N) ((N)&(-(N)))
const int MOD=1000000007;
const int MAXN=100005;
int N,Ans,Orig[MAXN],Sorted[MAXN],BinTree[MAXN<<2];
int BinSearch(int Goal)
{
int L=1,R=N;
while(L<=R)
{
int M=MID(L,R);
if(Sorted[M]==Goal) { return M; }
if(Sorted[M]<Goal) { L=M+1; }
if(Sorted[M]>Goal) { R=M-1; }
}
}
void Insert(int InsID,int InsVal)
{
while(InsID<=N)
{
BinTree[InsID]=(BinTree[InsID]+InsVal)%MOD;
InsID+=LOWBIT(InsID);
}
}
int Query(int QueID)
{
int sum=0;
while(QueID)
{
sum=(sum+BinTree[QueID])%MOD;
QueID-=LOWBIT(QueID);
}
return sum;
}
int main()
{
while(scanf("%d",&N)==1)
{
Ans=0;
memset(BinTree,0,sizeof(BinTree));
for(int i=1;i<=N;++i)
{
scanf("%d",&Orig[i]);
Sorted[i]=Orig[i];
}
sort(Sorted+1,Sorted+1+N);
for(int i=1;i<=N;++i)
{
int index=BinSearch(Orig[i]);
int sum=Query(index)+1;
Ans=(Ans+sum)%MOD;
Insert(index,sum);
}
printf("%d\n",Ans);
}
return 0;
}