Find the nondecreasing subsequences
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2225 Accepted Submission(s): 862
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
3
1 2 3
Sample Output
7
题目意思很简单,一句话,对于问题规模为10w求出所有非递减子序列的数量。
dp的状态转移方程即为 dp[j] = (Σ(i from 1 ~ j-1 && h[i]<=h[j])dp[i])+1
然后得到一个 O(n²)的算法,这样肯定是过不去的。
然后队友教我用线段树去维护。
求dp[j]时,需要求之前所有下标高度小于h[j] 的dp[i]之和。
可以发现 dp[i] i ∈ {i|i<j and h[i] <= h[j]}
所以只要对h[N]进行一次排序,得到h[i]到新下标的映射, (他们管这个叫离散化)
再从前向后扫一边h[N]即可保证i集合的条件。
说了这么多不如直接看代码。
由于有线段树维护 复杂度削减至 O(n log(n))
#include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <unordered_map> #include <set> #include <map> using namespace std; const unsigned int N = 100005; typedef long long ll; typedef unsigned int iu; const int mod = 1000000007; ll dp[N<<2u]; void build(iu l,iu r,iu rt){ dp[rt] = 0; if(l==r){ return; } iu m = (l+r)>>1u; build(l,m,rt<<1u); build(m+1,r,rt<<1u|1u); } void pushUp(iu rt){ dp[rt] = (dp[rt<<1u]+dp[rt<<1u|1u])%mod; } ll query(iu L,iu R ,iu l,iu r,iu rt){ if(L <= l and r <= R){ return dp[rt]; } iu m = (l+r)>>1u; ll ans = 0; if(m>=L)ans=query(L,R,l,m,rt<<1u); if(m<R)ans+=query(L,R,m+1,r,rt<<1u|1u); return ans%mod; } void upDate(iu loc,ll val,iu l,iu r,iu rt){ if(l==r){ dp[rt]+=val; dp[rt]%=mod; return; } iu m = (l+r)>>1u; if(m>=loc)upDate(loc,val,l,m,rt<<1u); if(m<loc)upDate(loc,val,m+1,r,rt<<1u|1u); pushUp(rt); } map<ll,iu>reflect;///unordered_map 用迭代器访问不一定有序; ll h[N]; int main(){ int n; while (cin>>n){ reflect.clear(); for(int i = 1 ; i <= n ; ++i){ scanf("%lld",h+i); reflect[h[i]] = 0; } iu cnt = 0; for(auto &i :reflect){///细节 auto i : reflect 无法更改其中数值 i.second = ++cnt; } iu k = reflect.size(); build(1,k,1); long long ans ; for(int i = 1 ; i <= n ; ++i){ iu pos = reflect[h[i]]; ans = query(1,pos,1,k,1); upDate(pos,ans+1,1,k,1); } printf("%lld ",query(1,k,1,k,1)); } }
数据结构真有意思;
另外HDU 3607和本题类似不妨一做
HDU 3607 题解传送门
https://www.cnblogs.com/xusirui/p/9396145.html