问题:解决
q
q
q次询问,每次询问
[
L
,
R
]
[L,R]
[L,R]中有多少对
(
i
,
j
)
,
满足
a
i
=
=
a
j
(i,j),满足a_i==a_j
(i,j),满足ai==aj
先想点超时但是可以解决的方法:
对于每次询问,枚举
L
<
=
i
<
=
R
L<=i<=R
L<=i<=R中的元素,令
n
u
m
[
i
]
num[i]
num[i]为
i
i
i元素出现的次数,显然这样的对数是
n
u
m
[
i
]
∗
(
n
u
m
[
i
]
−
1
)
/
2
num[i]*(num[i]-1)/2
num[i]∗(num[i]−1)/2
注意下题目似乎是静态的,并不是动态的。也许可以利用这点.
然而并没有想出来,据说是一种叫莫队的算法。
学习完莫队,发现这是莫队的板子题,真是富有启发性。
利用查询区间之间的信息,进行信息合并,很美妙的一个算法.
/*
Tonight I wanna drown in an ocean of you
*/
#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9+7;
const int maxn = 1e6+5;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int mx;
struct Node{
int l,r,id;
bool operator < (const Node &rhs)const{
if(l/mx!=rhs.l/mx) return l<rhs.l;
if((l/mx)&1) return r < rhs.r;
return r>rhs.r;
}
};//询问序列
Node q[maxn];
ll sum = 0;int cnt[maxn];int a[maxn];
void add(int i){
sum += cnt[i];
cnt[i]++;
}
void del(int i){
cnt[i]--;
sum -= cnt[i];
}
ll gcd(ll a,ll b){
if(!b) return a;
return gcd(b,a%b);
}
ll ans1[maxn],ans2[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;cin>>n>>m;
mx = n / sqrt(n*2/3);
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=0;i<m;i++) cin>>q[i].l>>q[i].r,q[i].id = i;
sort(q,q+m);
for(int i=0,l=1,r=0;i<m;i++){
if(q[i].l==q[i].r){
ans1[q[i].id] = 0,ans2[q[i].id] = 1;
continue;
}
while(l>q[i].l) add(a[--l]);
while(r<q[i].r) add(a[++r]);
while(l<q[i].l) del(a[l++]);
while(r>q[i].r) del(a[r--]);
ans1[q[i].id] = sum; //分子
ans2[q[i].id] = 1LL*(r-l+1)*(r-l)/2; //分母
}
for(int i=0;i<m;i++){
if(ans1[i]!=0){
ll g = gcd(ans1[i],ans2[i]);
ans1[i]/=g,ans2[i]/=g;
}
else ans2[i] = 1;
cout<<ans1[i]<<"/"<<ans2[i]<<"\n";
}
}