2020 CCPC Wannafly Winter Camp Day7 A(求任何子序列中相鄰範圍內數的個數的總和)
阿新 • • 發佈:2020-10-22
題:https://ac.nowcoder.com/acm/contest/4138/A
題意:給定一個1~n的序列,在任意長度大於等於2的子序列中,假設相鄰的為x,y,那麼若min(x,y)<=k<=max(x,y),那麼詢問的k增加1的貢獻,問k為1~n的答案為多少
分析:考慮每個i 和 j (i<j)對k的貢獻,假設對k有貢獻,那麼合法的區間有2i-1 * 2n-j ;
即對k而言,考慮[1,k-1] 和 [k+1,n]的匹配對數;
假設我們已經算出k,那麼對於k+1,即考慮[1,k] 和 [k+2,n];
我們發現實際上就從k那裡加上 [k] 和 [k+2,n]的貢獻,減去 [1,k-1] 和 [k+1] 的貢獻;
用樹狀陣列處理差分陣列b[]即可,最後將陣列反轉一遍再做相同處理即可;
#include<bits/stdc++.h> using namespace std; const int mod=1e9+7; const int M=1e5+5; typedef long long ll; int a[M],n; ll b[M],mi[M]; struct BIT{ ll tr[M+5]; void init(){ memset(tr,0,sizeof(tr)); } void add(int x,ll c){ for(int i=x;i<M;i+=i&-i) tr[i]=(tr[i]+c)%mod; } ll sum(View Codeint x){ ll res=0; for(int i=x;i;i-=i&-i) res=(res+tr[i])%mod; return res; } }bit; void solve(){ bit.init(); for(int i=n;i>=1;i--){ ll val=(bit.sum(n)-bit.sum(a[i]+1)+mod)%mod;///[a[i]+2,n]作為右端點 val=val*mi[i-1]%mod; b[a[i]+1]=(b[a[i]+1]+val)%mod; bit.add(a[i],mi[n-i]); } bit.init(); for(int i=1;i<=n;i++){ if(a[i]>2){ ll val=bit.sum(a[i]-2);///上面處理的是a[i]+1,所以減去的部分要對應上a[i]+1,因此要減去2 val=val*mi[n-i]%mod; b[a[i]]=(b[a[i]]-val+mod)%mod; } bit.add(a[i],mi[i-1]); } } int main(){ mi[0]=1; scanf("%d",&n); for(int i=1;i<=n;i++) mi[i]=mi[i-1]*2ll%mod; for(int i=1;i<=n;i++) scanf("%d",&a[i]); solve(); reverse(a+1,a+1+n); solve(); ll ans=0; for(int i=1;i<=n;i++){ ans=(ans+b[i])%mod; printf("%lld\n",ans); } return 0; }