时间: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;
}