首页 > 试题广场 >

编程题2

[编程题]编程题2
  • 热度指数:10763 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解

有n个房间,现在i号房间里的人需要被重新分配,分配的规则是这样的:先让i号房间里的人全都出来,接下来按照 i+1, i+2, i+3, ... 的顺序依此往这些房间里放一个人,n号房间的的下一个房间是1号房间,直到所有的人都被重新分配。

现在告诉你分配完后每个房间的人数以及最后一个人被分配的房间号x,你需要求出分配前每个房间的人数。数据保证一定有解,若有多解输出任意一个解。


输入描述:
第一行两个整数n, x (2<=n<=10^5, 1<=x<=n),代表房间房间数量以及最后一个人被分配的房间号;
第二行n个整数 a_i(0<=a_i<=10^9) ,代表每个房间分配后的人数。


输出描述:
输出n个整数,代表每个房间分配前的人数。
示例1

输入

3 1
6 5 1

输出

4 4 4
import java.util.Scanner;
/**
 * <a href=https://interview.nowcoder.com/questionTerminal/43068a1013b4417a85c2c2ce8b18159e>牛客描述</a>
 * 思路:分配后的房间里,人数最少的那一个房间就是i号房间。如果有多个房间人数最少,则取x号房间往前数的第一个人最少的房间。综上:无论哪种情况,从x房间往前数找到的第一个人最少的房间就是i号房间。
 * 找出i号房间后,就很容易求出之前的人数了。首先根据i号房间最后的人数确定完整的轮数,然后从x号往前再减去最后不足一轮的部分,然后把多出的人数全部补到第i个房间,就结束了
 * @author LBW
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int x = scanner.nextInt() - 1;
        long[] room = new long[n];
        long min = Long.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            room[i] = scanner.nextInt();
            if (room[i] < min)
                min = room[i];
        }
        //get min_index
        int minIndex = x;
        while (room[minIndex] != min) {
            minIndex = minIndex > 0 ? minIndex - 1 : n - 1;
        }
        // remove the round number.
        for (int i = 0; i < n; i++) {
            room[i] -= min;
        }
        // remove the tail
        int remain = 0;
        for (int i = x; i != minIndex; i = i > 0 ? i - 1 : n - 1) {
            room[i] -= 1;
            remain += 1;
        }
        room[minIndex] += remain + n * min;
        //print the result
        for (int i = 0; i < n; i++) {
            System.out.print(room[i] + " ");
        }
    }
}

发表于 2018-11-07 09:58:05 回复(4)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n, x;
    scanf("%d%d", &n, &x);
    long a[n], s=0, Min=LONG_MAX;
    for(int i=0;i<n;i++){
        scanf("%ld", &a[i]);
        if(a[i] < Min)
            Min = a[i];
    }
    int k = x-1;
    while(a[k] != Min)
        k = (k+n-1)%n;
    for(int i=0;i<n;i++)
        a[i] -= Min;
    for(int i=x-1;i!=k;){
        a[i]--;
        s++;
        i = (i+n-1)%n;
    }
    a[k] += s + n*Min;
    for(int i=0;i<n;i++)
        printf("%ld ", a[i]);

    return 0;
}

发表于 2020-12-09 00:32:49 回复(0)
很简单,python3.5代码:(总共14行)

def room(n, x, a):
    b = a[x:] + a[:x]
    b.reverse()
    m = min(b)
    i = b.index(m)
    for j in range(n):
        b[j] -= m
    for j in range(0,i):
        b[j] -= 1
    b[i] = i+m*n
    b.reverse()
    b = b[n-x:] + b[:n-x]
    for i in b:
        print(i, end = ' ')

发表于 2019-04-12 16:08:41 回复(0)
初始时 4 4 4 最后的结果不应该是 6 4 2 吗? 怎么能是6 5 1呢?
    4  4  4
4 * 0  4  4
       1  1
    1  1
————————
    1  6  5
6 * 1  0  5
          1
    1  1  1
    1  1
————————
    3  2  7
7*  3  2  0
    1  1  1
    1  1  1
    1
————————
    6  4  2

发表于 2019-06-13 10:58:25 回复(2)
有一说一啊,这题目描述跟💩一样
发表于 2021-02-22 16:10:36 回复(0)
要用stringbuilder
using System;
using System.Text;
public class Program {
    public static void Main() {
        string line;
        while ((line = System.Console.ReadLine ()) != null) { // 注意 while 处理多个 case
            string[] tokens = line.Split();
            long n = long.Parse(tokens[0]);
            long x = long.Parse(tokens[1]);
           
            string[] tokens1 = System.Console.ReadLine ().Split();
            long[] arr  = new long[n];
            for(long i=0;i<n;i++)
                arr[i] = long.Parse(tokens1[i]);
            long record = 0;//记录已经分配了多少个人
            long index = x-1;//记录当前访问位置
            long start = x-1;//起点位置
            //找到起点
            for(long i=0;i<n;i++)
            {
                index = (index-1+n)%n;
                if(arr[index] < arr[start])
                    start = index; // x之前第一个最小值的位置就是起点位置
            }
            //arr所有数减 arr[start] - 1,把起点转化成0
            long del = arr[start];
            for(long i=0;i<n;i++)
                arr[i] -= del;
            record += del * n;
            long j=x-1;

            while(j!=start )
            {
                arr[j]--;
                j = (j-1+n)%n;
                record ++;
            }
            arr[start] += record;
            StringBuilder sb  = new StringBuilder(arr[0].ToString());
            for(long i=1;i<n;i++)
                sb.Append(" "+ arr[i].ToString());
            Console.WriteLine(sb.ToString());
        }
    }
}

发表于 2023-11-26 15:57:23 回复(0)
这题为什么会有动态规划的标签啊
发表于 2022-06-12 02:29:56 回复(0)
基本思路:
#0.令p=x
#1.判断p号房间人数是否大于0,是则房间人数-1(让原本在i号房间的人出来),然后p自减1(如果为0则变为n),否则进入#3
#2.重复#1
#3.此时p号房间人数为0,即一开始的i号房间就是现在的p号房间,将#1中所有出来的人重新扔进p号房间,此时n个房间就处于一开始的状态
用这个运行后发现时间复杂度是O(a_i),会超时,只需要稍微做一点优化即可:先找出人数最少的房间,该房间有y个人,所有房间人数减去y(快速循环y*n次#1),然后再执行以上步骤,时间复杂度为O(n)
package main

import (
	"fmt"
)

func main() {
	var n, x int
	_, err := fmt.Scanf("%d %d", &n, &x)
	for err == nil {
		x--
		rooms := make([]int, n)
		if n == 0 {
			_, err = fmt.Scanf("%d %d", &n, &x)
			continue
		}
		fmt.Scan(&(rooms[0]))
		min := rooms[0]
		for i := 1; i < n; i++ {
			fmt.Scan(&(rooms[i]))
			if rooms[i] < min {
				min = rooms[i]
			}
		}
		for i := 0; i < n; i++ {
			rooms[i] -= min
		}

		p := x
		i := min * n
		for rooms[p] != 0 {
			rooms[p]--
			p = (p + n - 1) % n
			i++
		}
		rooms[p] += i
		for _, room := range rooms {
			fmt.Printf("%d ", room)
		}
		fmt.Println()

		_, err = fmt.Scanf("%d %d", &n, &x)
	}
}

发表于 2022-04-08 00:29:47 回复(0)
服了,😅
发表于 2022-03-05 19:58:30 回复(0)
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
int maxn= 1000000000;
using namespace std;
int main(){
    int n,x;
    vector<int> r;
    scanf("%d %d",&n,&x);
    int temp;
    x--;
    scanf("%d",&temp);
    int min=maxn;
    int minD=x;
    int t=1;
    for(int i=0;i<n;i++){
        r.push_back(temp);
        scanf("%d",&temp);
        if((min==temp&&abs(i+1-x)<abs(minD-x))||min>temp){
            min=temp;
            minD=i+1;
        }
    }
    int i=0,count=min+1;
    if(minD<=x){
    for(i=0;i<minD;i++){
        r[i]-=min;
        count+=min;
    }
        for(i=minD+1;i<x;i++){
            r[i]-=min+1;
            count+=min+1;
        }
        for(i=x+1;i<n;i++){
            r[i]-=min;
            count+=min;
        }
    }
    else{
        for(i=0;i<x;i++){
        r[i]-=min+1;
        count+=min+1;
    }
        for(i=x+1;i<minD;i++){
            r[i]-=min;
            count+=min;
        }
        for(i=minD+1;i<n;i++){
            r[i]-=min+1;
            count+=min+1;
        }
    }
        r[x]-=min+1;
        r[minD]+=count;
    for(int i=0;i<n;i++) printf("%d ",r[i]);
    return 0;
}
    

10 个1000000000过不了:(
数字太大了:(

发表于 2021-09-25 20:29:31 回复(0)
i 号房间开始分配时人数清空了,所以分配完成时人数一定是最小的。如果最小值有多个,那么选 x 之前的那个。
i 号房间分配后的人数等于分配的(轮数 - 1)。所有房间先减掉(轮数 - 1), i 到 x 之间的房间额外被分配一轮,单独减 1。
第 18 组用例输出末尾多了个「...」对不上,不知为何。
#include <iostream>
#include <climits>
using namespace std;

int main() {
    int n, x;
    cin >> n >> x;
    auto as = new unsigned long long[n];
    int min = 0;
    for (int i = 0; i < n; ++i) {
        cin >> as[i];
        if (as[i] < as[min]) {
            min = i;
        } else if (as[i] == as[min] && i < x) {
            min = i;
        }
    }
    unsigned long long rounds = as[min];
    for (int i = 0; i < n; i++) {
        as[i] -= rounds;
    }
    unsigned long long moved = rounds * n;
    x--;
    while (x != min) {
        --as[x--];
        ++moved;
        if (x < 0) {
            x = n - 1;
        }
    }
    as[min] = moved;
    for (int i = 0; i < n; i++) {
        cout << as[i] << ' ';
    }
}


发表于 2021-07-25 11:57:06 回复(1)
可以直接将整个过程倒着进行一次,同时也可以确定是从哪个房间开始的
#include <bits/stdc++.h>
using namespace std;
int main(int argc,char** argv){
    ios_base::sync_with_stdio(false); cin.tie(NULL);
    int n,x,i,j;
    cin>>n>>x;
    long input[n],min=1000000009;
    for(int i=0;i<n;i++){
        cin>>input[i];
        if(input[i]<min) min=input[i];
    }
    i=x-1;
    while(input[i]!=min) i=(i+n-1)%n;
    for(int j=x-1;j!=i;j=(j+n-1)%n) input[j]--;
    for(int j=0;j<n;j++) input[j]-=min;
    input[i]=n*min+(x-1-i+n)%n;
    for(int i=0;i<n;i++) cout<<input[i]<<" ";
}



发表于 2021-06-12 10:56:21 回复(1)
#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<limits.h>
#include<math.h>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
    int n,x;
    cin>>n>>x;
    vector<long long> arr(n,0);
    long long minnum=INT_MAX;
    for(int i=0;i<n;i++) {
        cin>>arr[i];
        minnum=min(minnum,arr[i]);
    }
    for(int i=0;i<n;i++) {
        arr[i]-=minnum;
    }
        
    int pos=x-1;
    long long ans=minnum*1L*n;
    while(arr[pos]!=0) {
        ans++;
        arr[pos]--; //原来分配给该房间的人还给第i个
        pos=(pos+n-1)%n; //往前推
    }
    arr[pos]=ans;
    for(int i=0;i<arr.size()-1;i++)
        cout<<arr[i]<<" ";
    cout<<arr[arr.size()-1]<<endl;
    return 0;
}

发表于 2021-05-18 20:14:58 回复(0)
#include<iostream>
using namespace std;

int main(void)
{
    int n, m;
    cin >> n >> m;
    int* arr;
    arr = new int[n];
    for (int i = 0; i < n; i++)
    {
        cin >> arr[i];
    }
    long long sum = 0, minx;
    for (int i = m - 1; i >= 0; i--)
    {
        arr[i]--; sum++;
    }
    minx = arr[0];
    for (int i = 1; i < n; i++)
    {
        if (minx > arr[i])
        {
            minx = arr[i];
        }
    }
    for (int i = 0; i < n; i++)
    {
        arr[i] -= minx;
    }
    int miny;
    for (int i = n-1; i >= 0; i--)
    {
        if (arr[i] == 0)
        {
            miny = i; break;
        }
    }
    for (int i = miny+1; i < n; i++)
    {
        arr[i]--; sum++;
    }
    for (int i = 0; i < n; i++)
    {
        if (i != miny)
            cout << arr[i]<<" ";
        else
            cout << n * minx + sum << " ";
    }
}
先从最后一个人分配的房间往后减并且记录人数,然后找出最小的一个数,所有房间都减去这个人数,从右往左第一个为0的房间就是一开始的房间,然后再从最后一个房间一直往前减到这个房间,把最终减的所有人数放回这个房间就得到了最初的结果
发表于 2021-03-31 10:36:54 回复(0)
太菜了。。。竟然被坑了两下
1. 房间编号是从1开始
2. 注意数据范围,要用long long
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100010];
int main(){
    int n, x;
    cin>>n>>x;
    x = x-1;
    for(int i = 0; i<n;i++) cin>>a[i];
    ll minima = INT_MAX, p=-1;
    for(int i = 1;i<=n;i++){
        int ii = (i+x) % n;
        if(a[ii]<=minima){
            minima= a[ii];
            p = ii;
        }
    }
    // cout<<minima<<" "<<p<<endl;
    if(x==p){
        for(int i=0;i<n;i++) a[i]-=minima;
        a[x] = minima*n;
    }else{
        bool flag = true;
        for(int i =1;i<n;i++){
            int ii = (p+i)%n;
            a[ii] -= minima+flag;
            a[p] += minima+flag;
            if(ii == x) flag = false;
        }
    }
    
    for(int i =0;i<n;i++){
        cout<<a[i]<<" ";
    }
}


发表于 2020-08-23 16:38:44 回复(0)
脑子笨,只会回溯
import java.util.*;

/**
 * @description: 方法1:递归回溯
 * @author: HP
 * @date: 2020-08-23 8:44
 */
public class Main {

    static int n;
    static int x;

    private static int getPre (int index) {
        return index - 1 == 0 ? n : index - 1;
    }

    private static int getTheFirstMinIndex (long[] rooms, long min) {
        for (int i = x; ; i = getPre(i)) {
            if (rooms[i] == min) {
                return i;
            }
        }
    }

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()){
            n = scanner.nextInt();
            x = scanner.nextInt();
            long[] rooms = new long[n + 1];
            for (int i = 1; i <= n; i ++) {
                rooms[i] = scanner.nextLong();
            }
            long min = Integer.MAX_VALUE;
            List<Integer> mins = new ArrayList<>();

            for (int i = 1; i <= n ; i ++) {
                if (rooms[i] < min) {
                    min = rooms[i];
                }
            }

            //方法1 找到许多最小的 , 一个个尝试,不行的话回溯
            for (int i = 1; i <= n; i ++) {
                if (rooms[i] == min) {
                    mins.add(i);
                }
            }

            //方法2
//            MD 要是我能直接知道 x (包括x自己)之前第一个最小的就是真的起点的话, 就好了,没看出来,烦死
//            mins.add(getTheFirstMinIndex(rooms, min));

            for (int index : mins) {
                if (tryDo(index, rooms, min)) {
                    for (int i = 1; i <= n ; i ++) {
                        System.out.print(rooms[i] + " ");
                    }
                }
                /**
                 * 记得结束
                 */
                return;
            }

        }
    }

    public static boolean doOperation (long[] rooms, int start, int end, long del) {
        for (int i = start; i <= end ; i ++) {
            rooms[i] += del;
            if (rooms[i] < 0) {
                doOperation(rooms, start, i, - del);
                return false;
            }
        }
        return true;
    }

    public static boolean doEqual (long[] rooms, int index, long del) {
        if (del < 0) {
            return false;
        }
        rooms[index] = del;
        return true;
    }

    public static boolean tryDo (int minIndex, long[] rooms, long min) {
        if (minIndex < x) {
            return doOperation(rooms, minIndex + 1, x, -min - 1)
                    && doOperation(rooms, x + 1, n, -min)
                    && doOperation(rooms, 1, minIndex - 1, - min)
                    && doEqual(rooms, minIndex, (n - x + minIndex - 1) * min
                    + (x - minIndex) * (min + 1) + rooms[minIndex]);
        } else {
            if (x == minIndex) {
                return doOperation(rooms, 1, n, - min) && doEqual(rooms, x, (n) * min);
            } else {
                return doOperation(rooms, minIndex + 1, n, -min - 1)
                        && doOperation(rooms, 1, x, - min - 1)
                        && doOperation(rooms, x + 1, minIndex - 1, - min)
                        && doEqual(rooms, minIndex, (minIndex - x - 1) * min
                        + (x + n - minIndex) * (min + 1) + rooms[minIndex]);
            }
        }
    }
}


发表于 2020-08-23 10:41:17 回复(0)
#include <bits/stdc++.h>

using namespace std;
typedef long long ll; // !!!不能用int,有些cases会溢出!!!

int main()
{
    int n, last;
    cin >> n >> last;
    vector<ll> nums(n);
    for(ll& i:nums){cin >> i;}
    last -= 1; //向量下标应该从0开始
​
    ll min_val = *min_element(nums.begin(), nums.end());
    for(ll& i:nums){i -= min_val;}
    ll count = min_val * nums.size();
    while(nums[last] > 0)
    {
        --nums[last];
        ++count;
        --last;
        if(last == -1){last = n - 1;}
    }
    nums[last] = count;
​
    for(auto& i:nums){cout << i << ' ';}
    return 0;
}
发表于 2020-07-21 03:37:33 回复(0)
//我脑子比较差,将minIndex和x谁先谁后分开讨论了,感觉用两个例子就很容易说明,就是花了很长时间才全部通过测试用例和平时做题感觉难度大好多
#include<iostream>
#include<vector>
#include<algorithm>
#include<limits.h>

using namespace std;

int main() {
    int n, x;
    cin >> n >> x;
    long*a = new long[n];
    long pmin = INT_MAX;
    for (int i = 0; i < n; ++i) {//找到最小值!
        cin >> a[i];
        pmin = min(pmin,a[i]);
    }
    //确定初始房间位置,最小值的位置不一定是初始位置
    int minIndex = x - 1;//最后一个插入位置的索引。
    //考虑如果有多个相同的最小值,那么原来都是0,和初始房间一样加入了相同的个数,
    //这些相同的最小值可能出现在i前,也可能出现在后面,而在这种情况下,初始房间i肯定在最后一个
    //插入之前,若是在最后一个插入后面,那么初始房间肯定是唯一最小值!而且最靠近最后一个插入位置
    while (a[minIndex] != pmin) {
        minIndex = minIndex > 0 ? minIndex - 1 : n - 1;//如果在x-1位置之前找不到最小值,那么说明最小值在最后插入的后面
    }
    //求初始位置的初始人数
    long initialPeople = minIndex<=x-1?n*(a[minIndex])+(x-1-minIndex):
        n*a[minIndex]+(n-(minIndex+1)+x);
    //首先所有位置是减去minIndex位置的值
    long  k = a[minIndex];
    for(int i=0;i<n;i++)
        a[i]-=k;
    if (minIndex > x - 1) {
        for (int i = 0; i <= x - 1; i++)
            a[i] -= 1;
        for (int j = n - 1; j > minIndex; j--)
            a[j] -= 1;
    }
    else {
        for (int i = minIndex; i < x; i++)
            a[i] -= 1;
    }
    a[minIndex] = initialPeople;
    for (int i = 0; i < n; i++) {
        cout << a[i]<<" ";
    }
    system("pause");
    return 0;
}


编辑于 2019-07-08 12:22:54 回复(0)
#include<iostream>
#include<limits.h>
 
using namespace std;
 
int main()
{
    int n,x;
    cin >> n >> x;
    long a[n],pmin = INT_MAX;
    for(int i = 0; i < n; ++i)
    {
        cin >> a[i];
        pmin = min(pmin,a[i]);
    }
    // 找到第一个最小的房间 确定为初始i房间
    int minroom = x -1;
    while(a[minroom] != pmin)
    {
        minroom = minroom > 0 ? minroom - 1 : n - 1;
    }
    // 每个房间都减去最小房间的人数,相当于n轮减1
    for(int i = 0; i < n; i++)
        a[i] -= pmin;
    int remain = 0;
    for(int i = x - 1; i != minroom;)
    {
        a[i] -= 1;
        remain++;
        i = i > 0? i - 1:n - 1;
    }
    a[minroom] += pmin*n + remain; // i房间的人数等于最小房间人数*n + 从i-1房间到最后一个分配房间的距离
    for(int i = 0; i < n - 1; ++i)
        cout << a[i] << " ";
    cout << a[n-1] << endl;
    return 0;
}

发表于 2019-05-09 20:16:58 回复(3)
#include<iostream>
using namespace std;
//封闭回路,用链表比较好
struct ListNode{
    ListNode(long long xx):item(xx),next(NULL){};
    long long item;ListNode* next;
};
int main(){
    int n,x;cin>>n>>x;ListNode* head=new ListNode(0);
    ListNode* end=head;
    for(int i=0;i!=n;++i){
        long long t;cin>>t;end->next=new ListNode(t);end=end->next;
    }
    head=head->next;end->next=head;
    end=head;
    while(--x)end=end->next;
    ListNode* p=end->next;ListNode* k;long long min=1e9;
    while(p!=end){//最后一间往前回,到自身为止最近的即是起始房间k
        if(p->item<=min)min=p->item,k=p;
        p=p->next;
    }
    if(p->item<=min)min=p->item,k=p;
    long long res=k->item*n;ListNode* start=k->next;p=head;long long j=k->item;
    for(int i=0;i!=n;++i){
        p->item-=j;p=p->next;
    }
    while(start!=end->next){
        start->item--;res++;start=start->next;
    }
    k->item=res;
    p=head;
    for(int i=0;i!=n;++i){
        cout<<p->item<<' ';p=p->next;
    }
}
发表于 2019-05-05 16:11:55 回复(0)