• P1494 [国家集训队] 小 Z 的袜子


    这一题是一个关于多次查询区间状态的一个问题,暴力肯定会超限,但是可以用莫队来优化暴力。

    莫队的思想就是,用上一个区间的状态来更新当前区间的状态。

    问题就是状态怎么更新以及求出当前区间的状态、也就是有多少对相同的袜子以及总共有多少袜子,通过这两个值可以求出来概率。

    如何求出来有多少对相同的袜子,只需要遍历一遍当前区间记录每个颜色出现了多少次,当到了某个位置的时候,只需要知道之前的袜子有多少能跟自己配对即可。从区间中删除某个袜子也是如此,减去区间中跟自己颜色相同的袜子即可。

    解释的不太好,看代码吧还是。

    1. #include
    2. #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    3. #define endl "\n"
    4. //#define x first
    5. //#define y second
    6. #define int long long
    7. using namespace std;
    8. typedef long long ll;
    9. typedef pair<int, int> pii;
    10. typedef pair<int, string> pis;
    11. typedef struct{
    12. int l, r, i;
    13. }aa;
    14. const int mod = 1e9 + 7;
    15. const int N = 1e6+ 10;
    16. int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
    17. int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
    18. int n, m;
    19. int o[N], f[N][2];
    20. aa p[N];
    21. int x, y;
    22. int st[N], s;
    23. inline void add(int a) // 加上当前位置
    24. {
    25. // 首先需要知道之前一共有多少袜子颜色跟自己相同,就是当前袜子可以跟之前的组成多少对。
    26. s += st[o[a]] ++;
    27. // 加完之后把这个颜色的袜子加一
    28. }
    29. inline void del(int a) // 减去当前位置
    30. {
    31. // 先是把当前的袜子从区间内减去,
    32. // 然后需要知道区间内一共有多少袜子颜色跟自己相同,就是当前袜子可以跟区间内的袜子组成多少对。
    33. s -= -- st[o[a]];
    34. }
    35. inline void query(int i, int l, int r) // 记录当前区间的概率, i表示是第i个问题,因为要按顺序输出
    36. {
    37. if(s == 0) // 特判不能组成袜子
    38. {
    39. f[i][0] = 0, f[i][1] = 1;
    40. return ;
    41. }
    42. int k = r - l + 1;
    43. k = k * (k - 1) / 2; // 这两行通过组合数求出不分颜色可以组成多少对袜子。
    44. int a = __gcd(k, s); // 化简为最简分数,需要计算出来最大公约数。
    45. // cout << s << " " << k << " " << a << endl;
    46. f[i][0] = s / a, f[i][1] = k / a; // 记录分子、分母。
    47. }
    48. int id[N];
    49. inline void sovle()
    50. {
    51. st[0] = 1;
    52. cin >> n >> m;
    53. int len = sqrt(n);
    54. for(int i = 1; i <= n; i ++)
    55. {
    56. cin >> o[i];
    57. id[i] = (i - 1) / len + 1;
    58. }
    59. for(int i = 0; i < m; i ++)
    60. {
    61. cin >> p[i].l >> p[i].r;
    62. p[i].i = i;
    63. }
    64. stable_sort(p, p + m, [&](aa a, aa b){ // 莫队特殊的排序方式
    65. if(id[a.l] == id[b.l])
    66. {
    67. if(id[a.l] & 1 == 1) return a.r < b.r;
    68. else return a.r > b.r;
    69. }
    70. else
    71. return id[a.l] < id[b.l];
    72. });
    73. int l = 0, r = 0, k = 0;
    74. for(int i = 0; i < m; i ++)
    75. {
    76. while(r > p[i].r) del(r --);
    77. while(r < p[i].r) add(++ r);
    78. while(l > p[i].l) add(-- l);
    79. while(l < p[i].l) del(l ++); // 这四部可以通过之前的区间移动到当前区间,在移动的过程中进行计算。
    80. query(p[i].i, p[i].l, p[i].r); // 记录当前区间的概率
    81. }
    82. for(int i = 0; i < m; i ++)
    83. {
    84. cout << f[i][0] << "/" << f[i][1] << endl;
    85. }
    86. }
    87. signed main(void)
    88. {
    89. IOS;
    90. int t = 1;
    91. // cin >> t;
    92. while(t --) sovle();
    93. return 0;
    94. }

  • 相关阅读:
    Leetcode Hot 100之四:283. 移动零+11. 盛最多水的容器
    hash表
    move_base代码阅读
    图新地球:如何添加视频到地图上,点击直接播放,汇报更顺畅
    多线程服务器端的实现
    测试开发日记:locust压测带你小试牛刀
    L46.linux命令每日一练 -- 第七章 Linux用户管理及用户信息查询命令 -- w和who
    SVG鼠标漫游
    Linux--网络编程
    FANUC机器人SRVO-050碰撞检测报警原因分析及处理对策(亲测可用)
  • 原文地址:https://blog.csdn.net/qq_64468032/article/details/134087508