题: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 ",ans); } return 0; }