[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}\)

此题通过贡献思想巧妙的将问题简单化。

posted @ 2020-10-25 15:58  东北小蟹蟹  阅读(45)  评论(0编辑  收藏