P1494 小Z的袜子 【普通莫队】

我的第二道莫队题,对莫队又有了自己的看法。

在第一题的基础上之上,觉得莫队有个很关键的地方在于 莫队所维护的值是什么,怎么推出维护的公式来。

这道题就是这样,一开始还没自己推出公式来,也有几个坑点。

题目链接:https://www.luogu.org/problemnew/show/P1494

 

题目大意:给出区间值,询问给定的【l, r】区间内抽到两只颜色一样的概率是多少。

思路:

1.首先很重要的推出公式来,设颜色相同的数量分别为a, b, c...那么对于给定的区间【l, r】,概率为 (a * (a  - 1) / 2+ b * (b - 1) / 2 + c * (c - 1) / 2 + ...) / ((r - l + 1) * (r - l) / 2),化简为 (a ^ 2 + b ^ 2 + c ^2 + ... - (r - l + 1)) / ((r - l + 1) * (r - l)),因此cnt维护区间内的值的数量,再推出如何维护平方和的值就行了。

2.计算的数据会爆int,需要用long long ,并且计算的式子要 * 1ll 来转化成long long型,才不会WA。

3.区间 l == r, 分子分母小于等于0时,直接记录 0 / 1

代码如下:

  1 #include<stdio.h>
  2 #include<math.h>
  3 #include<algorithm>
  4 using namespace std;
  5 const int MAXN = 50010;
  6 
  7 int arr[MAXN];
  8 int cnt[MAXN]; //区间内出现次数
  9 
 10 struct Qurey
 11 {
 12     int l, r, id;
 13     int pos; //所属的块 
 14 }q[MAXN];
 15 
 16 struct ANS
 17 {
 18     long long fz, fm;
 19 }ans[MAXN];
 20 
 21 bool cmp(Qurey a, Qurey b)
 22 {
 23     if(a.pos == b.pos)
 24         return a.r < b.r;
 25     else
 26         return a.pos < b.pos;
 27 }
 28 
 29 long long gcd(long long a, long long b)
 30 {
 31     long long c;
 32     while(b)
 33     {
 34         c = a % b;
 35         a = b;
 36         b = c;
 37     }
 38     return a;
 39 }
 40 
 41 int main()
 42 {
 43     int n, m;
 44     scanf("%d%d", &n, &m);
 45     for(int i = 1; i <= n; i ++)
 46         scanf("%d", &arr[i]);
 47     int fk = sqrt(n);
 48     for(int i = 1; i <= m; i ++)
 49     {
 50         scanf("%d%d", &q[i].l, &q[i].r);
 51         q[i].id = i;
 52         q[i].pos = (q[i].l - 1) / fk + 1;
 53     }
 54     sort(q + 1, q + 1 + m, cmp);
 55     int left = 1, right = 0;
 56     long long sum = 0;
 57     for(int i = 1; i <= m; i ++)
 58     {
 59         if(q[i].l == q[i].r)
 60         {
 61             ans[q[i].id].fz = 0;
 62             ans[q[i].id].fm = 1;
 63             continue;
 64         }
 65         while(left > q[i].l)
 66         {
 67             left --;
 68             cnt[arr[left]] ++;
 69             sum += 2 *1ll* cnt[arr[left]] - 1;
 70         }
 71         while(right < q[i].r)
 72         {
 73             right ++;
 74             cnt[arr[right]] ++;
 75             sum += 2 *1ll* cnt[arr[right]] - 1;
 76         }
 77         while(left < q[i].l)
 78         {
 79             cnt[arr[left]] --;
 80             sum -= 2 *1ll* cnt[arr[left]] + 1;
 81             left ++;
 82         }
 83         while(right > q[i].r)
 84         {
 85             cnt[arr[right]] --;
 86             sum -= 2 *1ll* cnt[arr[right]] + 1;
 87             right --;
 88         }
 89         long long fz = sum - (right - left + 1);
 90         long long fm = 1ll*(right - left + 1) * (right - left);
 91         if(fz <= 0 || fm <= 0)
 92         {
 93             ans[q[i].id].fz = 0;
 94             ans[q[i].id].fm = 1;
 95             continue;
 96         }
 97         long long temp = gcd(fz, fm);
 98         fz /= temp, fm /= temp;
 99         ans[q[i].id].fz = fz, ans[q[i].id].fm = fm;
100     }
101     for(int i = 1; i <= m; i ++)
102     {
103         printf("%lld/%lld\n", ans[i].fz, ans[i].fm);
104     }
105     return 0;
106 }
View Code

 

posted @ 2019-06-07 19:11  缘未到  阅读(111)  评论(0编辑  收藏  举报