传送门:BZOJ 2038
题意很明确,是在给定的区间内任意选取两个数,求选到两个相同的数的概率。
所以我们得首先统计在给定的区间内,相同的数对有多少对,那么这里就使用到了莫队算法。如果对莫队算法还不够了解,请百度一下,会有比较详细的解释,(虽然有一些也在瞎扯蛋),然后套模版就行了。其次这道题还需要用到一点组合数学知识,即C(n,r)=n!/[r! * (n-r)!]。设每次询问的区间长度为l,那么我们可以很快的计算出从l个数中任取两个的组合数为C(l,2)=l*(l-1)/2,套用公式即可。题目要求的概率也就是:区间内 相同的数对数/任取两个的组合数,再进行约分即可。
另外,因为n,m的最大值是50000,所以组合数可能会超过整型范围,所以本题需要开long long
代码如下:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <algorithm> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 #include <queue> 9 #include <string> 10 #include <map> 11 typedef long long ll; 12 using namespace std; 13 const int MAXN = 50005; 14 ll n, m; 15 ll L, R; 16 ll block; 17 ll c[MAXN]; 18 ll cnt[MAXN]; 19 ll ans; 20 ll s1[MAXN], s2[MAXN]; 21 22 struct like { 23 ll l, r; 24 ll No; 25 } qry[MAXN]; 26 27 inline ll gi() { 28 char c; 29 ll sum = 0, f = 1; 30 c = getchar(); 31 while (c < '0' || c > '9') { 32 if (c == '-') 33 f = -1; 34 c = getchar(); 35 } 36 while (c >= '0' && c <= '9') { 37 sum = sum * 10 + c - '0'; 38 c = getchar(); 39 } 40 return sum * f; 41 } 42 43 inline bool cmp(like a, like b) { 44 if (a.l / block != b.l / block) 45 return a.l < b.l; 46 return a.r < b.r; 47 } 48 49 inline void add(ll p) { 50 ans += cnt[c[p]]; 51 cnt[c[p]]++; 52 } 53 54 inline void remove(ll p) { 55 cnt[c[p]]--; 56 ans -= cnt[c[p]]; 57 } 58 59 inline void save(ll p, ll a, ll b) { 60 if (a == 0) { 61 s1[qry[p].No] = 0; 62 s2[qry[p].No] = 1; 63 return; 64 } 65 ll tpa = a, tpb = b; 66 if (tpa < tpb) 67 swap(tpa, tpb); 68 while (tpb) { 69 ll r = tpa % tpb; 70 tpa = tpb; 71 tpb = r; 72 } 73 s1[qry[p].No] = a / tpa; 74 s2[qry[p].No] = b / tpa; 75 } 76 77 int main() { 78 n = gi(); 79 m = gi(); 80 for (ll i = 1; i <= n; i++) 81 c[i] = gi(); 82 for (ll i = 1; i <= m; i++) { 83 qry[i].l = gi(); 84 qry[i].r = gi(); 85 qry[i].No = i; 86 } 87 block = sqrt(n); 88 sort(qry + 1, qry + m + 1, cmp); 89 L = 1; 90 R = 1; 91 cnt[c[1]] = 1; 92 for (ll i = 1; i <= m; i++) { 93 while (L < qry[i].l) { 94 remove(L); 95 L++; 96 } 97 while (L > qry[i].l) { 98 L--; 99 add(L); 100 } 101 while (R > qry[i].r) { 102 remove(R); 103 R--; 104 } 105 while (R < qry[i].r) { 106 R++; 107 add(R); 108 } 109 ll l = qry[i].r - qry[i].l + 1; 110 save(i, ans, l * (l - 1) / 2); 111 } 112 for (ll i = 1; i <= m; i++) 113 printf("%lld/%lld\n", s1[i], s2[i]); 114 return 0; 115 }