问题 A: 鲁的学生
时间限制: 1.000
题目描述
在宇宙大帝 Luke 的星球 Lu3KO5 上,有一所著名的星际学院,专门培养年轻的星际探险家们。在这一天,Luke 亲自担任数学导师,为这些年轻学员们组织了一场有趣的课堂活动。
Luke 让他的学生们站成一排,一共有 n 位学员。每位学员将随意选择一个代表他们能力值的数字 A[i]。接着,Luke 提出了一项挑战:在这些学员中,可以任意选择两名学员,并将他们之间的所有学员作为一个小组(包括这两名学员)。小组中的每个人所拿到的数字之和被称为该小组的“总分数”。
现在,Luke 想知道,如果将所有可能的小组都计算一遍,他们的“总分数之和”会是多少。由于结果可能非常庞大,请你帮助他计算这个结果对 1000000007 取模后的值。
输入
第一行输入一个非负整数 n
第二行输入 n 个非负整数,表示 A[i]
输出
输出一个整数,即答案
样例输入
3
1 2 3
样例输出
20
提示
样例解释:
若选择1则和为1。
若选择[1,2]则和为1+2=3。
若选择[1,3]则和为1+2+3=6。
若选择[2,2]则和为2。
若选择[2,3]则和为2+3=5。
若选择[3,3]则和为3。
对于前 30% 的数据 \(1≤n≤100\)
对于前 60% 的数据 \(1≤n≤1000\)
对于 100% 的数据 \(1≤n≤10^7, 0≤A[i]≤50000\)
分析
模拟答案可以得到,设第i个数为\(a_i\)
- 当长度为一的区间,每个数被和加入一次,
- 长度为2,除了\(a_1\) 和 \(a_n\),其余的数字都被加入两次(滑动)
- 长度为3的时候,除了\(a_1\) 和 \(a_n\)被加入一次,\(a_2\)和\(a_n_1\)被加入两次,其余的数字都被加入三次
- 虑下标为 i 的数字 a[i]。在所有连续区间中,要保证 a[i] 被包含,区间的左端点必须在 1 到 i 之间,右端点必须在 i 到 n 之间。
左端点有 i 种选法,右端点有 (n-i+1) 种选法,因此 a[i] 出现在的连续区间总数为
\(i × (n-i+1)\)。 - 最终所有区间的总和即为每个数字 a[i] 乘以它出现的次数,再求和:
答案 = \(Σ (a[i] × i × (n-i+1)) (i 从 1 到 n)\)
代码
#include <iostream>
#include<queue>
#include<vector>
#include<bitset>
#include<cstring>
#include<unordered_map>
#define de(x) cout << (#x) << "=" << x << '\n';
using namespace std;
#define int long long
const int N = 1e7 + 5,M = 1e9+7;
int v[N];
// //快读: 注意这里是引用符号,就相当与对要赋值的变量进行操作
// inline void read(int &x){
// x = 0; int f = 1; char ch = getchar();
// while(ch < '0' || ch > '9'){
// if(ch == '-') f = -1;
// ch = getchar();
// }
// while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
// x = x * f;
// }
signed main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int n;cin >> n;int sum = 0;for(int i = 1;i <= n;++i){cin >> v[i];int t = min(i,n-i+1);int cn = t*n-t*(t-1);//de(cn);sum = v[i] * cn % M + sum;}cout << sum%M;}