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\n", ans[i][0], ans[i][1]); 97 } 98 } 99 return 0; 100 }