洛谷 Equalize the Remainders


洛谷没提供中文题面,这里大致翻译一下:

可以进行的操作:任选一个数加一。

一共有n个整数,还有一个约数m,n个数都对m进行求余,累计余数的数量,要求每个余数都有n/m个。

对于样例1的输入,余数0有4个,余数1有1个,余数2有1个,发现余数0比n/m=2还要多,需要把多出的部分平摊到余数1和余数2上,让他们都拥有2个。

分析

因为只能进行+1的操作,所以如果当前余数已经满了,就一直+1放到下一个余数未满的地方,显然贪心是正确的。

那么直接暴力模拟走起!

TLE代码

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+1;
 
int n,m,cnt[N],av,a[N],ans;
//cnt[i]=j,余数为i的有j个
 
signed main(){
    cin>>n>>m;
    av=n/m;
    for(int i=1,res;i<=n;++i){
        cin>>a[i],res=a[i]%m;
        if(cnt[res]<av)cnt[res]++;
        else{//余数满了
            while(cnt[a[i]%m]>=av)a[i]++,ans++;//往下找,累计+1的次数
            cnt[a[i]%m]++;
        }
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;++i)
        cout<<a[i]<<" ";
    return 0;
}

如果运气差的话可以发现每个a[i]都有可能会遍历m-1 ≈ m次,一共有n个,复杂度就是n*m,妥妥的T飞出去。

由于外部循环体的n是没法省略的,所以我们考虑将m优化成logm,如果会莫队的也可以优化成根号m。

内部的m复杂度一直在找下一个可以放的余数,换句话说就是下一个比当前大的未满余数,如果没找到,那就从0开始往后找。

上面那句标黑的,如果能想到lower_bound,那这道题就做完了,没想到就g(还有更好的做法,这里是蒟蒻做法)。

优化

因为要使用lower_bound来查找未满余数,所以要一开始就全部输入完毕,然后再把未满余数收集起来(放set里面比较方便),同时也要收集没放进去的数。

然后把没放进去的数,往set的余数里面放就行了。

AC代码

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+1;

int n,m,a[N],cnt[N],av,ans;
vector<int>v;
set<int>s;
//cnt[i]=j,余数i的数量为j

signed main(){
    cin>>n>>m;
    av=n/m;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        if(cnt[a[i]%m]<av)cnt[a[i]%m]++;
        else v.push_back(i);//放不下的下标
    }
    for(int i=0;i<m;++i)//余数还有剩的
        if(cnt[i]<av)s.insert(i);
    for(auto i:v){//把a[i]%m往余数有剩的地方放
        auto nxt=s.lower_bound(a[i]%m);
        if(nxt!=s.end()){//有比他大的
            ans+=*nxt-a[i]%m;
            a[i]+=*nxt-a[i]%m;
            cnt[*nxt]++;
            if(cnt[*nxt]==av)s.erase(nxt);
        }else{//如果没有直接放begin
            nxt=s.begin();
            ans+=m-a[i]%m+*nxt;
            a[i]+=m-a[i]%m+*nxt;
            cnt[*nxt]++;
            if(cnt[*nxt]==av)s.erase(nxt);
        }
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;++i)
        cout<<a[i]<<" ";
    return 0;
}

记得开long long,不开long long见祖宗(

相关推荐
载数而行5201 小时前
QT的五类布局
c++·qt·学习
故事和你912 小时前
sdut-程序设计基础Ⅰ-实验五一维数组(8-13)
开发语言·数据结构·c++·算法·蓝桥杯·图论·类和对象
载数而行5202 小时前
QT的QString类
c++·qt·学习
像污秽一样2 小时前
算法与设计与分析-习题4.2
算法·排序算法·深度优先·dfs·bfs
Storynone3 小时前
【Day20】LeetCode:39. 组合总和,40. 组合总和II,131. 分割回文串
python·算法·leetcode
bu_shuo3 小时前
Visual C++2010学习版(全国计算机等级二级考试版)安装记录
c++·cpp·visual c++·计算机二级
明明如月学长3 小时前
AI 更新太快学不过来?我用OpenClaw打造专属AI学习工作流
算法
黎阳之光3 小时前
【黎阳之光:以无线专网与视频孪生,赋能智慧广电与数字中国】
算法·安全·智慧城市·数字孪生
刀法如飞4 小时前
Agentic AI时代,程序员必备的算法思想指南
人工智能·算法·agent
刀法如飞4 小时前
Agentic AI时代程序员必备算法思想详解(附实战案例)
算法·ai编程·编程开发·agentic