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

 

posted @ 2020-10-21 22:00  starve_to_death  阅读(101)  评论(0编辑  收藏  举报