HDU 2227 Find the nondecreasing subsequences
阿新 • • 發佈:2018-09-27
long long 推出 int tdi 思想 algorithm 優化 lowbit ()
樹狀數組+dp
因為今天復習離散化於是手賤加了個離散化
題目大意
意思是給你一段序列,求裏面的最長不下降子序列的長度。
dp思想
這道題的dp方程非常的好推,看完題目的第一眼就已經推出了方程
設dp[i]表示以當前點為終點的序列方案。所以方程是
\[
dp[i] += (i>j\&\&a[i]\ge a[j])? dp[j]+1:1\ans=\sum_{i=1}^{n}dp[i]
\]
但是一看這種方法就是\(n^2\)的復雜度,明顯過不了,那怎麽辦呢?
優化
我們知道,我們最後求得一定是一個前綴和的形式,所以這個樹狀數組可以做的很好。
我們先將原數組從小到大排個序,然後尋找它的下標。
為什麽從小到大呢?因為從小到大的話我們求得一定是不下降子序列,那麽決定答案的就是原位置的下標。
我們可以二分查找它的下標,那麽在他下標之前的前綴和一定就是總的方案數。
然後在查詢的前綴合裏加1,就是答案。
不理解?舉個例子。
排序前: 1 2 5 4 3
排序後: 1 2 3 4 5
數組下標: 1 2 5 4 3
首先第一個值是1,它得下標是1,前綴是0,所以方案數是1
第二個值2,下標二,前綴和1,方案數2
下個值3,下標是3,位置是5,前綴和是3,方案數4
下個值4,下標是4,位置是4,前綴和是4,方案數是5
下個值5,下標是5,位置是3,前綴和是3,方案數是4
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define LL long long using namespace std; const int mod = 1000000007; int c[100001]; int n; int b[100001],cnt; LL tree[100001]; int a[100001]; bool cmp(int x,int y) { return x<y; } int lowbit(int k) { return k&(-k); } void add(int k,int val) { while(k<=n) { tree[k]+=val; k+=lowbit(k); } } int ask(int k) { int ans=0; while(k!=0) { ans = (ans+tree[k])%mod ; k-=lowbit(k); } return ans%mod; } int main() { while(scanf("%d",&n)!=EOF) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); memset(tree,0,sizeof(tree)); cnt=0; for(int i=1; i<=n; i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+1+n,cmp); for(int i=1; i<=n; i++) if(b[i]!=b[cnt])b[++cnt]=b[i]; for(int i=1; i<=n; i++)a[i]=lower_bound(b+1,b+1+cnt,a[i])-b; for(int i=1; i<=n; i++)c[i]=a[i]; sort(a+1,a+1+n,cmp); for(int i=1; i<=n; i++) { int id=lower_bound(a+1,a+1+n,c[i])-a; add(id,ask(id)+1); } printf("%d\n",ask(n)); } }
HDU 2227 Find the nondecreasing subsequences