• 一道好题——分治


    一道好题应该有一个简洁的题面。
    有一个长度为 n,初始全为 0 的序列 a,另有一个长度为 n 的序列 b,你希望将 a 变成 b,你可以执行如下两种操作:

    1 x:将 a 中所有值为 x 的数 +1+1。
    2 x:将 a 中下标为 x 的数 +1+1。

    你不需要最小化操作次数,但只能使用最多 2000020000 次操作。

    Input
    第一行 一个正整数 n(1≤n≤1000)。
    第二行  n 个非负整数 b1 ,⋯,bn (0≤ bi ≤n)描述序列 b。

    Output
    第一行一个整数 k 表示操作次数,你需要保证 0≤k≤20000。
    之后 k 行每行两个整数 ,1 x 或 2 x,表示一次操作。对于 1 x 类型的操作,你需要保证 0≤x≤n,对于 2 x 类型的操作,你需要保证 1≤x≤n。

    Input
    4
    2 4 3 1

    Output
    7
    1 0
    2 1
    2 2
    2 3
    2 2
    1 3
    2 3
     

    解析:

    考虑分治,将所有相等的数压在一起先,然后每次让后半截先 +1 然后就可以提出后半截变成子问题了。做完后半截再做前半截。
    这样大概是 nlogn 次。
    要先进行 后半截的操作,避免 1类型操作。

    这样造成的效果就是

    1 1 1 1        1 1 1 1
    1 1 2 1        1 1 2 1
    1 1 2 2        1 2 2 1
    1 1 3 3        1 3 3 1
    1 1 3 4        1 4 3 1
    1 2 3 4        2 4 3 1 
    (排序后)      (原序列)

    1. #include <bits/stdc++.h>
    2. using namespace std;
    3. #define int long long
    4. #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    5. typedef pair<int,int> PII;
    6. const int N=2e6+10;
    7. vector <PII> a;
    8. vector <PII> ans;
    9. int n;
    10. void dfs(int l,int r,int now)
    11. {
    12. if (l>r) return ;
    13. if (l==r)
    14. {
    15. while (now<a[l].first)
    16. {
    17. ans.push_back({2,a[l].second});
    18. now++;
    19. }
    20. return ;
    21. }
    22. else
    23. {
    24. while (now<a[l].first)
    25. {
    26. ans.push_back({1,now});
    27. now++;
    28. }
    29. int mid=l+r>>1;
    30. mid++;
    31. while (mid<=r&&a[mid].first<=now) mid++;
    32. if (mid<=r)
    33. {
    34. for (int i=mid;i<=r;i++) ans.push_back({2,a[i].second});
    35. dfs(mid,r,now+1);
    36. dfs(l,mid-1,now);
    37. }
    38. }
    39. }
    40. signed main()
    41. {
    42. ios;
    43. cin>>n;
    44. for (int i=1;i<=n;i++)
    45. {
    46. int x;
    47. cin>>x;
    48. a.push_back({x,i});
    49. }
    50. sort(a.begin(),a.end());
    51. dfs(0,a.size()-1,0);
    52. cout<<ans.size()<<endl;
    53. for (auto x:ans) cout<<x.first<<" "<<x.second<<endl;
    54. return 0;
    55. }

  • 相关阅读:
    1. 开篇辞和一些SQL语句基本概念
    除了console.log(),很多人不知道的其他方法console.table,console.dir,console.time等
    聊一聊mysql的MVC
    FastDFS 一文读懂
    Map介绍
    43、优惠券秒杀(超卖问题分析(乐观锁解决思路))
    Java开发面试常见问题总结
    Element UI + tree组件 + 面包屑 实现导航
    快速排序详解-java实现
    Docker学习笔记(三)
  • 原文地址:https://blog.csdn.net/m0_74403543/article/details/134509049