1. 程式人生 > 實用技巧 >2020 CCPC Wannafly Winter Camp Day7 A(求任何子序列中相鄰範圍內數的個數的總和)

2020 CCPC Wannafly Winter Camp Day7 A(求任何子序列中相鄰範圍內數的個數的總和)

題: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(
int 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; }
View Code