1 条题解
-
0
根据题意,易得下面两个计算公式:
- 当前数字小于等于转经的次数,则贡献为:
- 当前数字大于转经的次数,则贡献为:
经过观察,排序并不改变功德值计算,因为每个数字都可以独立计算的。我们可以先对原始数组从小到大进行排序,然后根据当前的转经的次数二分找到数组的下标,使得下标左侧(包含)均为①式,下标右侧均为②式。
前者我们可以使用前缀和预处理①式即可 计算,后者我们需要推出下面公式。
$$(a_{r+1} *2-r+1) *r/2 + (a_{r+2} *2-r+1) *r/2 + ... + (a_{n} *2-r+1) *r/2\\ = [(a_{r+1}+a_{r+2}+...+a_{n}) *2-(r-1)*(n-r)] *r/2\\ = [\sum_{i=r+1}^n (a_{i})*2-(r-1)*(n-r)] *r/2 $$预处理后缀和,我们即可 计算后者。
$$ans =\sum_{i=1}^r [(a_{i} + 1) *a_{i}/2] +[\sum_{i=r+1}^n (a_{i})*2-(r-1)*(n-r)] *r/2 $$时间复杂度:
const int maxn = 2e5 + 7; int n, k, a[maxn], b[maxn], c[maxn], mod = 1e9 + 7; int ksm(int a, int b) { int res = 1; while (b) { if (b % 2) res = res * a % mod; b /= 2; a = a * a % mod; } return res; } void solve() { int n, k; cin >> n >> k; int two = ksm(2, mod - 2); for (int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + 1 + n); for (int i = 1; i <= n; i++) { b[i] = ((((a[i] + 1) * a[i] % mod) * two % mod) + b[i - 1]) % mod; c[i] = (a[i] + c[i - 1]) % mod; } for (int i = 1; i <= k; i++) { int x; cin >> x; int l = 0, r = n; while (l < r) { int mid = (l + r + 1) / 2; if (a[mid] <= x) l = mid; else r = mid - 1; } int tmp = ((((c[n] - c[l]) * 2 - (x - 1) * (n - l)) % mod) + mod) % mod; int ans = (b[l] + (tmp * x % mod) * two) % mod; cout << ans << endl; } }
- 1
信息
- ID
- 3
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 3
- 上传者