
洛谷没提供中文题面,这里大致翻译一下:
可以进行的操作:任选一个数加一。
一共有n个整数,还有一个约数m,n个数都对m进行求余,累计余数的数量,要求每个余数都有n/m个。
对于样例1的输入,余数0有4个,余数1有1个,余数2有1个,发现余数0比n/m=2还要多,需要把多出的部分平摊到余数1和余数2上,让他们都拥有2个。
分析
因为只能进行+1的操作,所以如果当前余数已经满了,就一直+1放到下一个余数未满的地方,显然贪心是正确的。
那么直接暴力模拟走起!
TLE代码
- #include
- #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]
- else{//余数满了
- while(cnt[a[i]%m]>=av)a[i]++,ans++;//往下找,累计+1的次数
- cnt[a[i]%m]++;
- }
- }
- cout<
- for(int i=1;i<=n;++i)
- cout<" ";
- 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代码
- #include
- #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]
- else v.push_back(i);//放不下的下标
- }
- for(int i=0;i
//余数还有剩的 - if(cnt[i]
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);
- }
- }
-
-
相关阅读:
【埋点探针】微信小程序SDK安装
leetcode986. 区间列表的交集
core sound driver详解
elasticsearch(ES)分布式搜索引擎02——(DSL查询文档,搜索结果处理)
基于JARM指纹的C2识别
【java】26:JUnit
java: 错误: 不支持发行版本 5 java: 错误: 不支持发行版本8 java: 错误: 不支持发行版本17
使用Python构建强大的网络爬虫
电商管理系统
HTTP协议概览
-
原文地址:https://blog.csdn.net/qq_17807067/article/details/134329464