19_05_21校内训练[简单序列]

题意

定义一个序列的价值为其排序后所有位置(从1开始)乘以该位置元素的值的和,即∑i*ai。求一个长度为n的序列的所有连续子序列的价值和。


思考

一个序列的价值可看做所有的元素的和,加上所有无序二元组中较大的元素的值。

因此答案分为两部分:
1.所有可能序列的元素和的和。考虑一个点,算出有多少区间包含它既可。

2.无序二元组较大的元素的值。不难得出两个点之间的贡献是线性的,因此用树状数组维护所有小于等于某个数的位置和既可。正反各做一遍。


代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long int ll;
 4 const ll maxn=2E5+5;
 5 const ll mod=1E9+7;
 6 ll n,a[maxn],ans,m,tim[maxn];
 7 struct BIT
 8 {
 9     ll t[maxn];
10     int lowbit(int x)
11     {
12         return x&-x;
13     }
14     void add(int x,ll y)
15     {
16         while(x<=m)
17         {
18             t[x]=(t[x]+y)%mod;
19             x+=lowbit(x);
20         }
21     }
22     ll ask(int x)
23     {
24         if(x==0)
25             return 0;
26         ll sum=0;
27         while(x)
28         {
29             sum=(sum+t[x])%mod;
30             x-=lowbit(x);
31         }
32         return sum;
33     }
34     void clear()
35     {
36         for(int i=1;i<=m;++i)
37             t[i]=0;
38     }
39 }T;
40 void get(int g)
41 {
42     for(int i=1;i<=n;++i)
43     {
44         ans=(ans+a[i]*T.ask(a[i]-g)%mod*(n-i+1))%mod;
45         T.add(a[i],i);
46     }
47 }
48 int main()
49 {
50     ios::sync_with_stdio(false);
51     cin>>n;
52     for(int i=1;i<=n;++i)
53     {
54         cin>>a[i];
55         m=max(m,a[i]);
56     }
57     for(int i=1;i<=n;++i)
58         ans=(ans+a[i]*((n-i+1)+i+(n-i)*(i-1)%mod-1))%mod;
59     get(1);
60     T.clear();
61     reverse(a+1,a+n+1);
62     get(0);
63     cout<<ans<<endl;
64     return 0;
65 }
View Code
原文地址:https://www.cnblogs.com/GreenDuck/p/10900931.html