• 洛谷 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代码

    1. #include
    2. #define int long long
    3. using namespace std;
    4. const int N=2e5+1;
    5. int n,m,cnt[N],av,a[N],ans;
    6. //cnt[i]=j,余数为i的有j个
    7. signed main(){
    8. cin>>n>>m;
    9. av=n/m;
    10. for(int i=1,res;i<=n;++i){
    11. cin>>a[i],res=a[i]%m;
    12. if(cnt[res]
    13. else{//余数满了
    14. while(cnt[a[i]%m]>=av)a[i]++,ans++;//往下找,累计+1的次数
    15. cnt[a[i]%m]++;
    16. }
    17. }
    18. cout<
    19. for(int i=1;i<=n;++i)
    20. cout<" ";
    21. return 0;
    22. }

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

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

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

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

    优化

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

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

    AC代码

    1. #include
    2. #define int long long
    3. using namespace std;
    4. const int N=2e5+1;
    5. int n,m,a[N],cnt[N],av,ans;
    6. vector<int>v;
    7. set<int>s;
    8. //cnt[i]=j,余数i的数量为j
    9. signed main(){
    10. cin>>n>>m;
    11. av=n/m;
    12. for(int i=1;i<=n;++i){
    13. cin>>a[i];
    14. if(cnt[a[i]%m]
    15. else v.push_back(i);//放不下的下标
    16. }
    17. for(int i=0;i//余数还有剩的
    18. if(cnt[i]insert(i);
    19. for(auto i:v){//把a[i]%m往余数有剩的地方放
    20. auto nxt=s.lower_bound(a[i]%m);
    21. if(nxt!=s.end()){//有比他大的
    22. ans+=*nxt-a[i]%m;
    23. a[i]+=*nxt-a[i]%m;
    24. cnt[*nxt]++;
    25. if(cnt[*nxt]==av)s.erase(nxt);
    26. }else{//如果没有直接放begin
    27. nxt=s.begin();
    28. ans+=m-a[i]%m+*nxt;
    29. a[i]+=m-a[i]%m+*nxt;
    30. cnt[*nxt]++;
    31. if(cnt[*nxt]==av)s.erase(nxt);
    32. }
    33. }
    34. cout<
    35. for(int i=1;i<=n;++i)
    36. cout<" ";
    37. return 0;
    38. }

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

  • 相关阅读:
    【埋点探针】微信小程序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