强迫症的序列 牛客网 思维

强迫症的序列 牛客网 思维

题意

链接:https://ac.nowcoder.com/acm/contest/90/J
来源:牛客网。
小A是一个中度强迫症患者,每次做数组有关的题目都异常难受,他十分希望数组的每一个元素都一样大,这样子看起来才是最棒的,所以他决定通过一些操作把这个变成一个看起来不难受的数组,但他又想不要和之前的那个数组偏差那么大,所以他每次操作只给这个数组的其中n-1个元素加1,但是小A并不能很好的算出最优的解决方案,如果你能帮他解决这个问题,小A就能送你一个气球

输入:
第一行一个整数T(T<=100),表示组数
对于每组数据有一个n,表示序列的长度(0< n <100000)
下面一行有n个数,表示每个序列的值(0<\(ai\)<1000)

输出:
两个数
第一个数表示最小的操作步数
第二个数经过若干步以后的数组元素是什么

例如:
1
3
1 2 3
输出:
3 4

解题思路

这里有一个很奇怪的点,就是每次操作都需要选择\(n-1\)个数,然后对每个数都加1。这样我们可以反过来想:相当于选择一个数进行减一,然后使得所有的数都相同,这里很容易想到,既然是只能选择一个数进行减一操作,那我就只能把所有的数都减到这\(n\)个数中的最小值喽,因此我们就计算出了总的操作次数,即每个数和最小数的差的和。公式如下:\(a\)代表操作的次数。

\[a=\sum_{i=0}^{n-1}(a[i]-min) \quad \text{min代表最小值,数组从下标0开始存储} \]

这里操作次数计算出来了,但是最后我们把这些数实际变成了什么呢?也就是需要输出的第二个数。这里我们可以简单发现下面的公式,假设\(b\)就是需要输出的第二个数。

\[\begin{aligned}\underbrace{a*(n-1)+sum}_\text{这里是a次操作后,这n个数的总和}=\underbrace{n*b}_\text{这里也是a次操作后的n个数的总和} \quad \text{:sum代表这n个数原来的总和}\end{aligned} \]

这样我们就可以根据上面的公式就可以计算第二个需要的数\(b\)

\[\begin{aligned}b& = \frac{a*(n-1)+sum}{n} \\& = \frac{a*n+sum-a}{n} \\& = a+\frac{sum-a}{n}\end{aligned} \]

代码实现

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+7;
const int inf=0x3f3f3f3f;
int num[maxn];
int t, n, sum;
int main()
{
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        sum=0;
        int a=0, sum=0, minn=inf;
        for(int i=0; i<n; i++)
        {
            scanf("%d", &num[i]);
            minn=min(minn, num[i]);
            sum+=num[i];
        }
        for(int i=0; i<n; i++)
            if(num[i]>minn)
                a+=num[i]-minn;
        printf("%d %d\n", a, a+(sum-a)/n);//注意第二个表达式,这里要避免进行
    }
    return 0;
 }
posted @ 2019-11-28 21:05  ALKING1001  阅读(162)  评论(0编辑  收藏  举报