1 /* 2 题意:n,m<=50000 一个长度为n的区间,每个位置有一个颜色,查询一个区间[l,r]中取两个点颜色相同的概率。 3 题解:莫队算法, 统计当前区间每种颜色的个数. 4 时间:2018.07.20 5 */ 6 7 #include <bits/stdc++.h> 8 using namespace std; 9 10 typedef long long LL; 11 const int MAXN = 100005; 12 const LL MOD7 = 1e9+7; 13 14 struct Node 15 { 16 int l,r; 17 int idx; 18 }Q[MAXN]; 19 int belong[MAXN],qsize; // 分块 20 int a[MAXN]; // 颜色 21 LL flag[MAXN]; // 目前维护的区间中各种颜色的个数 22 LL ans[MAXN]; // 询问的答案 23 LL len[MAXN]; // 询问区间的长度 24 LL Ans; // 当前区间内的答案 25 int n,m; 26 27 28 // 按照分块的位置对所有的询问排序 29 int cmp(Node na,Node nb) 30 { 31 if (belong[na.l]==belong[nb.l]) 32 return na.r<nb.r; 33 return belong[na.l]<belong[nb.l]; 34 } 35 36 // 确定分块的位置 37 void build() 38 { 39 qsize = sqrt(n); 40 for (int i=1;i<=n;++i) belong[i] = (i-1)/qsize+1; 41 } 42 43 44 // 当前区间扩展一个点x,考虑x的颜色a[x],那么当前点对区间的贡献应该为区间中颜色为a[x]的个数即flag[a[x]] 45 void Add(int x) 46 { 47 Ans+=flag[a[x]]; 48 ++flag[a[x]]; 49 } 50 // 删除一个端点, 那么先把当前的颜色删除,然后删除当前颜色对区间的贡献 51 void Delete(int x) 52 { 53 --flag[a[x]]; 54 Ans-=flag[a[x]]; 55 } 56 57 LL gcd(LL a, LL b) 58 { 59 if (b==0) return a; 60 return gcd(b,a%b); 61 } 62 63 int main() 64 { 65 #ifndef ONLINE_JUDGE 66 freopen("test.txt","r",stdin); 67 #endif // ONLINE_JUDGE 68 scanf("%d%d",&n,&m); 69 for (int i=1;i<=n;++i) scanf("%d",&a[i]); 70 for (int i=1;i<=m;++i) 71 { 72 scanf("%d%d",&Q[i].l,&Q[i].r); 73 Q[i].idx=i; 74 len[i] = Q[i].r-Q[i].l+1; 75 } 76 build(); 77 sort(Q+1,Q+1+m,cmp); 78 memset(flag,0LL,sizeof(flag)); 79 Ans=0; 80 int l=1,r=0; 81 for (int i=1;i<=m;++i) 82 { 83 int idx=Q[i].idx; 84 // 查询的区间小于当前的区间,那么左端点右移,并且移动前删除端点的贡献 85 while (l<Q[i].l) { 86 Delete(l); 87 ++l; 88 } 89 // 查询的区间大于当前的区间,那么假如下面一个端点的贡献,左移区间端点 90 while (l>Q[i].l) { 91 Add(l-1); 92 --l; 93 } 94 // 95 while (r<Q[i].r) { 96 Add(r+1); 97 ++r; 98 } 99 while (r>Q[i].r) { 100 Delete(r); 101 --r; 102 } 103 ans[idx]=Ans; 104 } 105 for (int i=1;i<=m;++i) 106 { 107 LL tmp = len[i]*(len[i]-1); 108 LL d=gcd(2*ans[i],tmp); 109 // printf("%lld\n",2*ans[i]); 110 printf("%lld/%lld\n",2*ans[i]/d, tmp/d); 111 } 112 return 0; 113 }