1月3日 C题 小信的数组

时间:1s 空间:256M

题目描述:

有一个长度为 n 的数组 a。小信从第一个数开始执行下列操作直到sum=k:

if ai>0:sum+=1,ai−=1, then i=(i+1)modn。

问最后数组变成什么样。

输入格式:

第一行包含两个整数 n,k。

第二行包含 n 个整数 ai 。

输出格式:

输出 n 个整数表示答案。

样例输入:

3 4
1 3 2

样例输出:

0 1 1

约定与提示:

对于100%的数据,1≤n≤105,1≤k≤1e12, 0≤ai≤1e12。

对于样例,[1,3,2] - > [0,3,2] - > [0,2,2] - > [0,2,1] - > [0,1,1]。

题意:

根据对于样例可知sum=0,i=0,要输入n,k,n是输入整数的个数,k类似判断指标,只要sum不等于k就一直执行操作:判断ai是否大于0,大于0sum++,ai--......

思路:

这道题的k和ai最大有10的十二次方,所以int是不行的,要用long long,这道题看上去较为简单,可以用while判断sum是否等于k,之后按部就班就可以,然后就有了如下代码:

超时代码:

#include <bits/stdc++.h>
using namespace std;
long long n,k,sum=0;
long long a[100005]; 
int main(){
    cin>>n>>k;
    for(long long i=0;i<n;i++){
        scanf("%lld",&a[i]);
    }
    long long i=0;
    while(sum!=k){
        if(a[i]>0){
            sum++;
            a[i]--;

        }       
        i=(i+1)%n;
    }
    for(long long i=0;i<n;i++){
        printf("%lld ",a[i]);
    }
    return 0;
} 

思路:

但是这个代码是会超时的,只有20分,去看数据范围,1≤k≤1e12,遍历一定会超时,每个数至少减一次,复杂度都有(1e12)次。,所以我们要用另一种方法:

将一组数中某个数减至0前,操作是固定的,我们可以先把数组排序,同时我们可以将四个数字看成整个集体去减以达到优化的效果。我们减的过程中边减一边统计,每次减掉的数字之和为最小数*n,每一轮结束最小的数总是变成第二小的数字,我们将k-=数字之和这样就可以避免超时。

代码:

#include<bits/stdc++.h>
using namespace std;
pair<long long,long long>b[100005];
long long a[100005];
set<long long>s;
int main(){
    long long n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s.insert(i);
        b[i].first=i;
        b[i].second=a[i];
    }
    sort(b+1,b+1+n,[](pair<long long,long long> a,pair<long long,long long> b){
       return a.second<b.second;
    });
    long long sum=0,everysum=0;
    int id=1;
    while(sum+(b[id].second-everysum)*s.size()<k){
        sum+=(b[id].second-everysum)*s.size();
        s.erase(b[id].first);
        everysum=b[id].second;
        id++;
    }
    everysum+=(k-sum)/s.size();
    id=(k-sum)%s.size();
    if(id>0){
        everysum++;
    }
    sum=id;
    for(int i=1;i<=n;i++){
        if(id>0){
            if(s.count(i)&&sum>0){
                sum--;
                cout<<a[i]-everysum<<' ';
            }
            else{
                cout<<max(a[i]-everysum+1,(long long)0)<<' ';
            }
        }
        else{
            cout<<max(a[i]-everysum,(long long)0)<<' ';
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值