[CF1436A] Reorder
\(\mathtt{Link}\)
\(\mathtt{Summarization}\)
给定一个长度为 \(n\) 的序列 \(a\),求是否有一种排序方案使得 \(\sum_{i=1}^n\sum_{j=i}^n\dfrac{a_j}{j} = m\)。
\(\mathtt{Solution}\)
显然 \(a\) 序列中某些数字被处理并累加过若干次,不妨先把所有数处理掉,考虑每个都加了多少次。
比如这样一个序列:\(a_1, a_2, a_3, a_4, a_5\)
先处理该序列,变成:\(\dfrac{a_1}{1}, \dfrac{a_2}{2}, \dfrac{a_3}{3}, \dfrac{a_4}{4}, \dfrac{a_5}{5}\)。
那么问题就可以转化成这样一个被处理的序列,求是否 \(\sum_{i=1}^n\sum_{j=i}^na_j = m\)。
你会发现,在 \(a_j\) 这个位置的数正好被累计了 \(j\) 次。
因为 \(1 \le i \le j\) 的时候,每次累计了 \(1\) 次 \(a_j\),总共就是 \(j\) 次;但是当 \(j < i \le n\) 的时候,就累计不到 \(a_j\) 了。
那么问题其实要求的就是 \(\dfrac{a_1}{1} \times 1 + \dfrac{a_2}{2} \times 2 + \dfrac{a_3}{3} \times 3 + \dfrac{a_4}{4} \times 4 + \dfrac{a_5}{5} \times 5\)。你会惊奇的发现,分母都能和后面的乘数,相约,也就是最后变成了 \(a_1 + a_2 + a_3+a_4+a_5\)。
换句话讲,就是说 \(\sum_{i=1}^n\sum_{j=i}^n\dfrac{a_j}{j} = \sum_{i=1}^na_i\)。
问题也就转化成是否有一种排序方式使得这个序列的和为 \(m\)。
我们知道,因为加法交换律,因此在不加数不删数不改数的情况下,这个序列无论怎么排序,和都是固定的。
那么,
- 如果这个序列的和是 \(m\),就一定有解;
- 如果这个序列的和不是 \(m\),就没解了。
该算法时间复杂度为 \(\mathcal{O}(n)\)。
\(\mathtt{Code}\)
/*
* @Author: crab-in-the-northeast
* @Date: 2020-10-25 08:28:22
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-10-25 08:37:06
*/
#include <iostream>
#include <cstdio>
const int maxn = 10005;
int a[maxn];
int main() {
int t;
std :: scanf("%d", &t);
while (t--) {
int n, m;
std :: scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i)
std :: scanf("%d", &a[i]);
int sum = 0;
for (int i = 1; i <= n; ++i)
sum += a[i];
if (sum == m)
puts("YES");
else
puts("NO");
}
}
\(\mathtt{More}\)
此题通过贡献思想巧妙的将问题简单化。