首页 > 试题广场 >

还原数列

[编程题]还原数列
  • 热度指数:3618 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
老板给度度熊个数, 每一次从中取出一个最大的减去, 其他的个数加上, 一直重复直到最大的, 执行次数记为
老板想知道最少执行多少次操作使得个数都小于呢?

输入描述:
第一行一个数
第二行个数表示数列


输出描述:
一个数表示
示例1

输入

3
1 0 3

输出

1
56个民族,55加分,一个不加分===一个民族减分

import java.util.*;
 
public class Main{
    public static void main(String[] args){
             
             
             
        
        Scanner sc =new Scanner(System.in);
        int n =sc.nextInt();
        long [] arr =new long [n];
        for(int i =0;i<n;i++){
            arr[i]=sc.nextLong();
        }
        long count=0;
        int len=arr.length;
        while(!isVaild(arr)){
            long max=0;
            int index=0;
            for(int i =0;i<arr.length;i++){
                if(arr[i]>max){
                    max=arr[i];
                    index=i;
                }
            }
            count+=max/n;
            for(int i=0;i<n;i++){
                arr[i]+=max/n;
            }
            arr[index]=max%n;
        }
        System.out.println(count);
    }
    public static boolean isVaild(long [] arr){
        boolean falg =true;
        for(long i:arr){
            if(i>=arr.length) return false;
        }
        return falg;
    }
}


发表于 2021-06-21 00:57:00 回复(8)
let n = Number(readline());
let arr = readline().split(' ');
let k = 0;
while(true){
    let maxIndex = 0;
    for(let i in arr){
        if(arr[i]>arr[maxIndex])maxIndex = i
    }
    let max = arr[maxIndex];
    if(max<n)break;
    let step = Math.floor(max/n);
    //print(step,max,n);
    for(let i in arr){
        if(i!=maxIndex)arr[i] = +arr[i] + step
    }
    arr[maxIndex]-=step*n
    k+=step
}
print(k)
数值很大,n又很小的时候,k会很大,所以k不能一次只加1,会超时。一次要直接加上max/n取整
发表于 2021-12-08 21:04:36 回复(0)
这道题, 怎么测试,提交提示代码不通过?最起码告诉我们用什么类名?用什么方法名?然后用你们的测试用例来测试, 搞了半天都不知道这些规则, 你们能不能改进一些?
发表于 2021-09-05 11:39:49 回复(3)
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        long[] num = new long[a];
        for (int i = 0; i < a; i++) {
            num[i] = sc.nextLong();
        }
        long k = 0;
        Arrays.sort(num);
        while (num[a - 1] >= a) {
            //注意两点:1 long  2 避免超时 max/n
            long tmp = num[a-1]/a;
            num[a - 1] -= a*tmp;
            for (int i = 0; i < a - 1; i++) {
                num[i] += tmp;
            }
            Arrays.sort(num);
            k+=tmp;
        }
        System.out.println(k);

    }
}

发表于 2022-07-26 15:10:14 回复(2)
遍历数组,大于n说明在之后过程一定要减n,同时其他数字必定+1,建立数组保存这个信息,可以降低很多时间:
n = int(input())
ll = list(map(int, input().split()))
ll.sort()
res = 0
dp = [0] * n
while ll[-1] >= n:
    for i in range(n):
        dp[i] = ll[i] // n
    cursum = sum(dp)
    res += cursum
    for i in range(n):
        ll[i] = ll[i] - n * dp[i] + cursum - dp[i]
    ll.sort()
print(res)

发表于 2022-03-24 17:15:26 回复(1)
97ms,对着白云想了一下,不会超过2n^2+n轮。
方法还是模拟,但做了这两个优化:
1. 不必照着规则模拟最大的数下降,一次把某个值降到n以下吧
2. 既然每个值都+1,为什么不把目标值-1呢?
from heapq import *

n = int(input())
a = list(map(lambda s:-int(s), input().split()))

target_line = n
heapify(a)

op_time = 0
while True:
    peek = -a[0]
    if peek < target_line:
        print(op_time)
        break

    op = (peek - target_line) // (n+1) + 1

    after = peek - op * (n+1)
    heapreplace(a, -after)

    target_line -= op
    op_time += op

发表于 2022-04-10 15:48:07 回复(0)
思路:重复以下操作直到最大值小于 n,三次操作的复杂度是 O(log N + N + log N) = O(N)
 1. 从堆中获取最大值,O(log N)
 2. 将堆中所有的值加 1,O(N)
 3. 将最大值减去 n 放回堆,O(log N)
最终需要执行 k 次,那么总的时间消耗就是 O(k * N)
优化:设最大值是 max,每次最大值直接减去 max/n*n,让 max 直接变成一个小于 n 的数字,不用反复执行多次减一操作
因为 Java 提供的堆不能将堆中元素全部加上某个增量,所以我们需要自己实现一个堆
import java.util.*;

// 思路:重复以下操作直到最大值小于 n,三次操作的复杂度是 O(log N + N + log N) = O(N)
// 1. 从堆中获取最大值,O(log N)
// 2. 将堆中所有的值加 1,O(N)
// 3. 将最大值减去 n 放回堆,O(log N)
// 最终需要执行 k 次,那么总的时间消耗就是 O(k * N)
// 优化:设最大值是 max,每次最大值直接减去 max/n*n,让 max 直接变成一个小于 n 的数字,不用反复执行多次减一操作
public class Main {
    public static void main(String[] args) {
        // 读取数据
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        long[] nums = new long[n];
        for (int i = 0; i < n; ++i) {
            nums[i] = in.nextLong();
        }
        // 建堆
        Heap heap = new Heap(nums);
        // 操作
        long k = 0;
        long max = 0;
        while ((max = heap.poll()) >= n) {
            long count = max / n;
            heap.increment(count);
            heap.push(max % n);
            k += count;
        }
        System.out.println(k);
    }
}

class Heap {
    // 数组
    private long[] nums;
    // 堆的大小
    private int size;

    public Heap(long[] nums) {
        this.nums = nums;
        this.size = nums.length;
        buildHeap();
        //System.out.println(Arrays.toString(nums));
    }

    // 是否为树叶
    private boolean isLeaf(int i) {
        return i > size/2 - 1;
    }

    // 左儿子
    private int leftSon(int i) {
        return i * 2 + 1;
    }

    // 右儿子
    private int rightSon(int i) {
        return i * 2 + 2;
    }

    // 父节点
    private int parent(int i) {
        return (i - 1) / 2;
    } 

    // 建堆
    private void buildHeap() {
        for (int i = size/2 - 1; i >= 0; --i) {
            //System.out.println(i);
            filterDown(i);
        }
    }

    // 下滤
    private void filterDown(int i) {
        long value = nums[i];
        while (!isLeaf(i)) {
            int j = leftSon(i), rightSon = rightSon(i);
            // 有右儿子且右儿子更大
            if (rightSon < size && nums[j] < nums[rightSon]) {
                j = rightSon;
            }
            if (nums[j] > value) {
                nums[i] = nums[j];
                i = j;
            } else {
                break;
            }
        }
        nums[i] = value;
    }

    // 上滤
    private void filterUp(int i) {
        long value = nums[i];
        while (i > 0) {
            int parent = parent(i);
            if (value > nums[parent]) {
                nums[i] = nums[parent];
                i = parent;
            } else {
                break;
            }
        }
        nums[i] = value;
    }

    // 取出最大值
    public long poll() {
        long value = nums[0];
        nums[0] = nums[--size];
        filterDown(0);
        return value;
    }

    // 放入值
    public void push(long num) {
        nums[size++] = num;
        filterUp(size-1);
    }

    // 堆内的全部值加 1
    public void increment(long delta) {
        for (int i = 0; i < size; ++i) {
            nums[i] += delta;
        }
    }
}


发表于 2023-08-18 17:30:12 回复(0)
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        try(BufferedReader bf = new BufferedReader(new InputStreamReader((
                        System.in)))) {
            int n = Integer.parseInt(bf.readLine());
            Scanner in = new Scanner(System.in);
            long[] nums = new long[n];
            String[] strs = bf.readLine().split(" ");
            for (int i = 0; i < n; i++) {
                nums[i] = Long.parseLong(strs[i]);
            }
            long result = 0;
            //累积记录+1的数量
            long tag = 0;
            //循环数组思维(无需关注最大值),用于记录复原tag的数据(比如第一位数执行了k次减去n,则arr[0]=-k,tag=k,下次循环到第一位时,tag再加上arr[0]以次来复原tag(因为+1只影响它自身以外的数据))
            long[] arr = new long[n];
            do {
                for (int i = 0; i < n; i++) {
                    tag += arr[i];
                    nums[i] += tag;
                    arr[i] = -(nums[i] / n);
                    result -= arr[i];
                    nums[i] %= n;
                    tag -= arr[i];
                }
            } while (tag != 0);
            System.out.println(result);
        } catch (Exception e) {

        }

    }
}
编辑于 2023-06-07 08:26:51 回复(0)
#include<iostream>
#include<algorithm>
using namespace std;

//注意范围
typedef long long ll;

int main(){
    int N;
    cin>>N;
    ll a[N];
    for(int i=0;i<N;i++){cin>>a[i];}
    ll res=0;
    while(true){
        sort(a,a+N);
        if(a[N-1]<N){break;}
        //主要是下面这三行,将多次减法用除法+取模解决了,然后加法那里记得要加的是商
        ll div=a[N-1]/N;
        a[N-1]=a[N-1]%N;
        for(int i=0;i<N-1;i++){a[i]+=div;}
        res+=div;
    }
    cout<<res<<endl;
    return 0;
}

编辑于 2022-07-31 03:57:40 回复(0)
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        long[] nums = new long[n];
        for(int i = 0; i < n; i++){
            nums[i] = scanner.nextLong();
        }
        Arrays.sort(nums);
        long count = 0;
        while(nums[n - 1] >= n){
            long tmp = nums[n - 1] / n;
            for(int i = 0; i < n - 1; i++){
                nums[i] += tmp;
            }
            nums[n - 1] -= n * tmp;
            count += tmp;           
            Arrays.sort(nums);
        }      
        System.out.println(count);
    }
}
发表于 2022-03-21 15:38:06 回复(0)
n = int(input())
arr = input()
arr = arr.split(" ")
arr = list(map(int, arr))
k = 0
while True:
    tmp = max(arr)
    if tmp < n:
        break
    index = arr.index(tmp)
    arr = [x + tmp // n for x in arr]
    arr[index] = tmp % n
    k += tmp // n
print(k)
发表于 2021-07-17 15:14:40 回复(1)

献丑c++代码,5ms

  • 每次取最大值,计算减到小于n的次数k
  • 更新值
    需要保证数组有序,可以在每次循环的时候排序,也能过,因为n的范围很小。但可以二分查找插入位置再插入,这样只需要开头排序一次。
    因为每次循环只减少最大值(数组末尾)的数值,其他数值(1~n-1)本身就是有序的,增加相同的值也是有序的,所以将的值插入进去就行了。
#include <bits/stdc++.h>
using namespace std;

int main() {
    using ll = long long;
    multiset<ll> st;
    ll n;
    cin >> n;
    vector<ll> v;
    for (int k = 0; k < n; k++) {
        ll tmp;
        cin >> tmp;
        v.emplace_back(tmp);
    }
    std::sort(v.begin(), v.end());
    ll cnt = 0;
    while (v.back() >= n) {
        auto x = v.back();
        v.pop_back();
        ll k = (long long) (x * 1.0 / n - 1) + 1;
        cnt += k;
        x = x - k * n;
        for (auto& num : v) {
            num += k;
        }
        auto it = std::lower_bound(v.begin(), v.end(), x);
        v.insert(it, x);
    }
    cout << cnt;
}
发表于 2023-10-04 11:37:40 回复(0)
/*

   构建大根堆实现
*/


import java.util.Scanner;
import java.util.Arrays;
import java.util.Collections;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main{
    public static int n;
    public static Long[]f;//构建的大根堆
    public static long k=0;
 
    //对大根堆的index节点进行右旋操作
    public static void sort(int index){
        int left=2*index+1,right=2*index+2;//左右子树顶点
 
        if(left<n&&right<n){
            long max =0;
            int i=left;
            if(f[left]>f[right]){
                max = f[left];
            }else{
                max = f[right];
                i=right;
            }
            //交换
            if(max>f[index]){
                long temp = f[index];
                f[index]=f[i];
                f[i]=temp;
                sort(i);//继续向下
            }
        }else if(left<n){
            if(f[left]>f[index]){
                //交换
                long temp = f[index];
                f[index]=f[left];
                f[left]=temp;
                sort(left);//继续向下
            }
        }
 
        return;
        
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n=in.nextInt();
        f = new Long[n];
         
        //输入数据
        for(int i=0;i<n;i++){
            f[i]=in.nextLong();
        }
 
        Arrays.sort(f,Collections.reverseOrder());
         
         
        while(f[0]>=n){
            //直接减多少个
            long t = f[0]/n;
            f[0]-=t*n;
            for(int i=1;i<n;i++){
                f[i]+=t;
            }
            k+=t;
            sort(0);
        }
 
        System.out.println(k);
         
        in.close();
    }
     
}
发表于 2023-08-19 20:12:54 回复(0)
每轮把所有的大于n的都变成nums[i]%n
import java.util.*;


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        long[] nums = new long[n];
        long sum = 0;
        for(int i=0;i<n;i++){
            nums[i]=in.nextLong();
            sum +=nums[i]/n;
        }
        boolean exceedn = true;
        long tempsum=0,lastsum=sum;
        while(exceedn){
            exceedn=false;
            for(int i=0;i<n;i++){
                long tempadd = lastsum-nums[i]/n;
                nums[i]= (nums[i]%n)+tempadd;
                tempsum += (nums[i]/n);
            }
            if(tempsum>0){
                exceedn=true;
                sum += tempsum;
                lastsum=tempsum;
                tempsum=0;
            }
        }
        System.out.println(sum);
    }
}


发表于 2023-07-30 21:54:16 回复(0)
import java.util.Scanner;

/**
 * 还原数列
 */
public class Main5 {
    public static void main(String[] args) {
        long k=0;
        // xcrj
        int n=0;
        Scanner in=new Scanner(System.in);
        if(in.hasNextInt()){
            n=in.nextInt();
        }
        // xcrj
        long[] as=new long[n];
        for(int i=0;i<n&&in.hasNextLong();i++){
            as[i]=in.nextLong();
        }
        in.close();
        /**
         * 减法要想到/ %
         * 数组中的每个数字都会被减到小于n,遍历数组把每个数字都减到小于n
         * - as[i]/n, 被减ki次
         * - as[i]%n, 减ki次之后的余数, 是as[i]最后的值
         * - as[i]被减ki次,其它的数会加上ki个1
         */
        while(valid(as, n)){
            for (int i=0;i<n;i++){
                if(as[i]>=n){
                    long ki=as[i]/n;
                    k+=ki;
                    as[i]=as[i]%n;
                    for(int j=0;j<n;j++){
                        if(i!=j) {
                            as[j]+=ki;
                        }
                    }                
                }
            }
        }
        //
        System.out.println(k);
    }

    /**
     * 继续循环
     * 
     * @return true 存在as[i]>=n
     * @return false 不存在as[i]>=n
     */
    public static boolean valid(long[] as, int n) {
        for (long a : as) {
            if (a >= n) {
                return true;
            }
        }
        return false;
    }
}

发表于 2023-03-15 21:43:16 回复(0)
# python
n = int(input())
nums = list(map(int, input().split()))
res = 0
# 模拟 一次减去times次数
while max(nums) >= n:
    index = nums.index(max(nums))
    times = (nums[index]-n)//n + 1
    nums = [item + times for item in nums]
    nums[index] -= times*(n+1)
    res += times
print(res)


编辑于 2022-09-10 22:02:41 回复(1)
import java.io.*;
import java.util.*;
public class Main{
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = " ";
        while((str = br.readLine()) != null){
            String[] str_array = br.readLine().split(" ");
            long n = (long)str_array.length;
            PriorityQueue<Long> heap = new PriorityQueue<>((o1,o2)->{return o1.compareTo(o2) < 0? 1 :-1;});
            for(String value : str_array) heap.offer(Long.parseLong(value));
            Queue<Long> queue = new LinkedList<>();
            long result = 0;
            while(true){
                long max = heap.poll();
                if(max < n) break;
                long step = max / n;
                queue.offer(max % n);
                while(heap.size() != 0) queue.offer(heap.poll()+step);
                while(queue.size() != 0) heap.offer(queue.poll());
                result += step;
            }
            System.out.println(result);
        }
    }
}


发表于 2022-08-01 10:53:48 回复(0)
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        // long  a;
        // a=in.nextInt();
        int b=in.nextInt();
        long [] a=new long[b];
        for(int i=0;i<b;i++){
            a[i]=in.nextLong();
        }
        Arrays.sort(a);
        long count=0;
        while(a[b-1]>=b){
            count+=a[b-1]/b;//计算最大值可以减去多少个N
            for(int i=0;i<b-1;i++){
                a[i]+=a[b-1]/b;//直接每个值添加最大值可以减去多少个N的次数
            }
            a[b-1]=a[b-1]%b;//最大值小于N后的值
            Arrays.sort(a);
        }
        System.out.println(count);
    }
        }



编辑于 2022-04-10 19:20:26 回复(0)
这个题一看就是要用大顶堆去做
发表于 2021-10-18 13:48:57 回复(1)
package com.ff.baidu;

import java.util.Arrays;

public class unit2 {
    /*给一个长度为n的数组,每次都用数组中最大的数-n,
    其他的数+1,执行多少次数组里面所有的数都小于n*/
    public static int getCount(int[] arr){
//       计算数组的长度
        int n=arr.length;
        int count=0;//计录一共进行了多少次
        while (true){
//            给数组排序
            Arrays.sort(arr);
            if(arr[arr.length-1]<n){
                break;
            }
//            数组中最大的数-n
            arr[arr.length-1]=arr[arr.length-1]-n;
//            让其他数加1
            for (int i = 0; i <arr.length-1 ; i++) {
                arr[i]+=1;
            }
            count++;

        }

        return count;
    }

    public static void main(String[] args) {
       int [] arr={1,7,4};
        int count =getCount(arr);
        System.out.println(count);
    }
}

 

发表于 2021-08-26 10:32:01 回复(2)