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 }