1. 程式人生 > >【樹狀數組+dp+離散化】Counting Sequences

【樹狀數組+dp+離散化】Counting Sequences

spa amp def space pac ask sequence hide 復雜

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/G

【題意】

給定一個數組a,問這個數組有多少個子序列,滿足子序列中任意兩個相鄰數的差(絕對值)都不大於d.

【思路】

首先,樸素的dp思想:

dp[i]為以a[i]結尾的子問題的答案,則dp[i]=sum(dp[k]),k<i&&|a[k]-a[i]|<=d

但是時間復雜度為O(n^2),會超時。

我們可以這樣想:

如果數組a排好序後,dp[i]就是區間(a[i]-d,a[i]+d)的結果和(直接把a[i]加到原數組後面)

所以自然而然就想到了用樹狀數組,區間求和求出dp[i],然後單點修改dp[i]以備後用。

這樣時間復雜度就變成了O(nlogn)

另外要註意原來是很稀疏的大數據,我們要離散化壓縮狀態(排序去重)

【Accepted】

技術分享
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=9901;
 4 typedef long long ll;
 5 int n,d,cnt;
 6 int c[100010],a[100010];
 7 int h[100010];
 8 int lowbit(int x)
 9 {
10     return x&(-x);
11 }
12 void change(int x,int
y) 13 { 14 for(;x<=n;x+=lowbit(x)) 15 { 16 c[x]+=y; 17 c[x]%=mod; 18 } 19 } 20 int ask(int x) 21 { 22 int ans=0; 23 for(;x;x-=lowbit(x)) 24 { 25 ans+=c[x]; 26 ans%=mod; 27 } 28 return ans; 29 } 30 int main() 31 { 32 while(scanf("%d%d
",&n,&d)!=EOF) 33 { 34 cnt=n; 35 for(int i=1;i<=n;i++) 36 { 37 scanf("%d",a+i); 38 h[i]=a[i]; 39 c[i]=0; 40 } 41 sort(h+1,h+cnt+1); 42 cnt=unique(h+1,h+cnt+1)-h-1; 43 int ans=0; 44 for(int i=1;i<=n;i++) 45 { 46 int fi=1; 47 int l=lower_bound(h+1,h+cnt+1,a[i]-d)-h; 48 int r=upper_bound(h+1,h+cnt+1,a[i]+d)-h-1; 49 int pos=lower_bound(h+1,h+cnt+1,a[i])-h; 50 fi+=(ask(r)-ask(l-1)+mod)%mod; 51 fi%=mod; 52 ans+=fi; 53 ans%=mod; 54 change(pos,fi); 55 } 56 ans=(ans-n%mod+mod)%mod; 57 printf("%d\n",ans); 58 } 59 }
View Code

【樹狀數組+dp+離散化】Counting Sequences