小红的点赞(二)

[题目链接](https://www.nowcoder.com/practice/b5bd2d0d30154ae6bbd11b25b56dbd6d)

思路

本题的关键在于理解"不会出现一个笔记点赞数连续增加"这一约束。

分析

设所有笔记初始赞数为 ,总和为 ,最大值为

对于笔记 ,我们需要让它的赞数达到某个目标值 ),使得没有其他笔记超过

假设笔记 需要增加 次赞。由于不能连续给同一笔记点赞, 次点赞之间需要穿插至少 次对其他笔记的点赞。

次"其他点赞"分配给其他 个笔记,设笔记 )额外获得 次点赞,则需要满足:

$$

总可承受上限为 ,所以需要:

$$

代入 整理得:

$$

所以当 时,,答案为 时)或 时)。

特殊情况

  • :只有一个笔记,已是最大,答案直接为
  • :两个笔记 。每次给 加赞后必须给 加赞,两者交替增长。当 时, 永远追不上 ,输出 。否则只需至多 1 步即可追平。

举例

以样例 为例,

笔记 答案
1 3 1
2 1 4
3 4 0

代码

#include <bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<long long> a(n);
    long long S = 0, mx = 0;
    for(int i = 0; i < n; i++){
        cin >> a[i];
        S += a[i];
        mx = max(mx, a[i]);
    }
    if(n == 1){
        cout << a[0] << "\n";
        return 0;
    }
    for(int i = 0; i < n; i++){
        if(n == 2){
            int j = 1 - i;
            if(a[j] - a[i] > 1){
                cout << -1 << "\n";
            } else {
                long long T = max(a[i], a[j]);
                long long D = T - a[i];
                if(D == 0) cout << S << "\n";
                else cout << S + 2*D - 1 << "\n";
            }
        } else {
            long long num = S - 2*a[i] - 1;
            long long den = n - 2;
            long long T2;
            if(num <= 0){
                T2 = 0;
            } else {
                T2 = (num + den - 1) / den;
            }
            long long T = max(mx, T2);
            long long D = T - a[i];
            if(D == 0) cout << S << "\n";
            else cout << S + 2*D - 1 << "\n";
        }
    }
    return 0;
}
import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine().trim());
        StringTokenizer st = new StringTokenizer(br.readLine().trim());
        long[] a = new long[n];
        long S = 0, mx = 0;
        for (int i = 0; i < n; i++) {
            a[i] = Long.parseLong(st.nextToken());
            S += a[i];
            mx = Math.max(mx, a[i]);
        }
        StringBuilder sb = new StringBuilder();
        if (n == 1) {
            sb.append(a[0]).append("\n");
        } else {
            for (int i = 0; i < n; i++) {
                if (n == 2) {
                    int j = 1 - i;
                    if (a[j] - a[i] > 1) {
                        sb.append(-1).append("\n");
                    } else {
                        long T = Math.max(a[i], a[j]);
                        long D = T - a[i];
                        if (D == 0) sb.append(S).append("\n");
                        else sb.append(S + 2 * D - 1).append("\n");
                    }
                } else {
                    long num = S - 2 * a[i] - 1;
                    long den = n - 2;
                    long T2;
                    if (num <= 0) {
                        T2 = 0;
                    } else {
                        T2 = (num + den - 1) / den;
                    }
                    long T = Math.max(mx, T2);
                    long D = T - a[i];
                    if (D == 0) sb.append(S).append("\n");
                    else sb.append(S + 2 * D - 1).append("\n");
                }
            }
        }
        System.out.print(sb);
    }
}

复杂度分析

  • 时间复杂度,遍历数组一次求和与最大值,再遍历一次计算每个笔记的答案。
  • 空间复杂度,存储输入数组。