前言:
这题挺妙的。可能是我对数学计数题熟悉点,想了一会还是搞出来了。个人觉得1900左右。不能有2300的难度。
题目大意:
给你一个序列,问你每一个子数组 [ L , R ] [L,R] [L,R]经排序之后 ∑ i = 1 R − L + 1 a L + i − 1 ∗ i \sum_{i=1}^{R-L+1} a_{L+i-1}*i ∑i=1R−L+1aL+i−1∗i的总和.
即 ∑ i = 1 n ∑ j = i n ∑ k = i j a k ∗ ( k − i ) / / k 为 子 数 组 [ i , j ] 经 过 排 序 后 的 下 标 \sum_{i=1}^{n} \sum_{j=i}^{n} \sum_{k=i}^{j} a_{k}*(k-i) //k为子数组[i,j]经过排序后的下标 ∑i=1n∑j=in∑k=ijak∗(k−i)//k为子数组[i,j]经过排序后的下标
题目思路:
直接算显然不行,考虑单点的贡献,换更方便的统计方式。老技巧了。
对于第 i i i个位置,值为 a i a_i ai.我们可以将 ≤ a i \leq a_i ≤ai的数都标记成1.反之为0.因为小于等于 a i a_i ai的数会让 a i a_i ai的rank恰好上升1.那么序列大概变成了 0001101011001 这样的感觉.粗体代表 a i a_i ai的位置。
对于经过转变后的01数组,问题转化为求所有覆盖位置 i i i的子数组的区间和的总和。
直接算也显然不行,还是延续上面的老套路,我们继续考虑一个1对整体答案的贡献: i d j ∗ ( n − i + 1 ) id_j*(n-i+1) idj∗(n−i+1). i d j id_j idj代表第j个1的下标位置。
那么对于 i i i左侧的 1 1 1.答案就是 ∑ i d ∗ ( n − i + 1 ) \sum id*(n-i+1) ∑id∗(n−i+1).然后 r e v e r s e reverse reverse一下整个序列,再跑一遍算法即可。
这个过程我们发现我们需要记录一个 ≤ a i \leq a_i ≤ai的数的下标的前缀和。显然树状数组即可。
然后就没了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
ll a[maxn];
ll sum[maxn] , n;
int lowbit(int x){
return x & -x;}
void add(int x,ll c){
while(x<=n){
sum[x] = (sum[x] + c)%mod;
x += lowbit(x);
}
}
ll ask(int x){
ll ans=0;
while(x){
ans=(ans + sum[x])%mod;
x-=lowbit(x);
}
return ans;
}
ll dist[maxn] , cnt , c[maxn];
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1 ; i <= n ; i++){
cin >> a[i];
dist[++cnt] = a[i];
}
sort(dist + 1 , dist + 1 + cnt);
cnt = unique(dist + 1 , dist + 1 + cnt) - dist - 1;
for (int i = 1 ; i <= n ; i++)
a[i] = lower_bound(dist + 1 , dist + 1 + cnt , a[i]) - dist;
for (int i = 1 ; i <= n ; i++){
add(a[i] , i);
ll res = ask(a[i]) * (n - i + 1) % mod;
c[i] = (c[i] + res) % mod;
}
reverse(a + 1 , a + 1 + n);
reverse(c + 1 , c + 1 + n);
memset(sum , 0 , sizeof sum);
for (int i = 1 ; i <= n ; i++){
ll res = ask(a[i]) * (n - i + 1) % mod;
c[i] = (c[i] + res) % mod;
add(a[i] , i);
}
ll ans = 0;
for (int i = 1 ; i <= n ; i++){
c[i] = c[i] * dist[a[i]] % mod;
ans = (ans + c[i]) % mod;
}
cout << ans << endl;
return 0;
}