bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队算法

题目链接

给n个数, m个询问, 每个询问有[L, R]两个值, 在这段区间内取两个数,求这两个数相同的概率。

对于区间[L, R], 概率的分母显然是(R-L+1)*(R-L)/2, 对于分子, 假设我们已经有了一个1, 又遇到了一个1, 那么这时分子应该加上(2*1)/2, 假如又遇到了一个1, 那么分子应该减去(2*1)/2然后在加上(3*2)/2。

因为只有查询而没有修改, 所以我们可以离线做, 先将每一个区间读入, 然后将其排序,一开始的区间是[L, R], 对于下一个区间[L', R'], 只需要考虑[L, L']或[L', L]这一部分以及[R, R']或[R', R]这一部分。

分子就是这段区间内的sigma(s[i]*s[i-1])/2, s[i]是每一个数出现的次数。具体看代码。

注意会爆int

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define pb(x) push_back(x)
  4 #define ll long long
  5 #define mk(x, y) make_pair(x, y)
  6 #define lson l, m, rt<<1
  7 #define mem(a) memset(a, 0, sizeof(a))
  8 #define rson m+1, r, rt<<1|1
  9 #define mem1(a) memset(a, -1, sizeof(a))
 10 #define mem2(a) memset(a, 0x3f, sizeof(a))
 11 #define rep(i, a, n) for(int i = a; i<n; i++)
 12 #define ull unsigned long long
 13 typedef pair<int, int> pll;
 14 const double PI = acos(-1.0);
 15 const double eps = 1e-8;
 16 const int mod = 1e9+7;
 17 const int inf = 1061109567;
 18 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
 19 const int maxn = 50005;
 20 int a[maxn], b[maxn], ans[maxn][2];
 21 struct node
 22 {
 23     int block, r, l, id;
 24     bool operator < (node a)const
 25     {
 26         if(block == a.block)
 27             return r<a.r;
 28         return block<a.block;
 29     }
 30 }q[maxn];
 31 ll gcd(ll a, ll b) {
 32     return b==0?a:gcd(b, a%b);
 33 }
 34 void get(int l, int r, int id, ll tmp) {
 35     if(tmp == 0) {
 36         ans[id][0] = 0;
 37         ans[id][1] = 1;
 38     } else {
 39         ll g = gcd(tmp, 1ll*(r-l+1)*(r-l));
 40         ans[id][0] = tmp/g;
 41         ans[id][1] = 1ll*(r-l+1)*(r-l)/g;
 42     }
 43 }
 44 int main()
 45 {
 46     int n, m;
 47     while(~scanf("%d%d", &n, &m)) {
 48         mem(b);
 49         for(int i = 1; i<=n; i++) {
 50             scanf("%d", &a[i]);
 51         }
 52         int BLOCK = sqrt(n*1.0);
 53         for(int i = 0; i<m; i++) {
 54             scanf("%d%d", &q[i].l, &q[i].r);
 55             q[i].block = q[i].l/BLOCK;
 56             q[i].id = i;
 57         }
 58         sort(q, q+m);
 59         ll tmp = 0;
 60         for(int i = q[0].l; i<=q[0].r; i++) {
 61             tmp -= 1ll*b[a[i]]*(b[a[i]]-1);
 62             b[a[i]]++;
 63             tmp += 1ll*b[a[i]]*(b[a[i]]-1);
 64         }
 65         get(q[0].l, q[0].r, q[0].id, tmp);
 66         for(int i = 1; i<m; i++) {
 67             if(q[i].l<q[i-1].l) {
 68                 for(int j = q[i-1].l-1; j>=q[i].l; j--) {
 69                     tmp -= 1ll*b[a[j]]*(b[a[j]]-1);
 70                     b[a[j]]++;
 71                     tmp += 1ll*b[a[j]]*(b[a[j]]-1);
 72                 }
 73             } else {
 74                 for(int j = q[i-1].l; j<q[i].l; j++) {
 75                     tmp -= 1ll*b[a[j]]*(b[a[j]]-1);
 76                     b[a[j]]--;
 77                     tmp += 1ll*b[a[j]]*(b[a[j]]-1);
 78                 }
 79             }
 80             if(q[i].r>q[i-1].r) {
 81                 for(int j = q[i-1].r+1; j<=q[i].r; j++) {
 82                     tmp -= 1ll*b[a[j]]*(b[a[j]]-1);
 83                     b[a[j]]++;
 84                     tmp += 1ll*b[a[j]]*(b[a[j]]-1);
 85                 }
 86             } else {
 87                 for(int j = q[i-1].r; j>q[i].r; j--) {
 88                     tmp -= 1ll*b[a[j]]*(b[a[j]]-1);
 89                     b[a[j]]--;
 90                     tmp += 1ll*b[a[j]]*(b[a[j]]-1);
 91                 }
 92             }
 93             get(q[i].l, q[i].r, q[i].id, tmp);
 94         }
 95         for(int i = 0; i<m; i++) {
 96             printf("%d/%d
", ans[i][0], ans[i][1]);
 97         }
 98     }
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/yohaha/p/5057152.html