输入格式
第一行包含两个正整数 N N N 和 M , N M,N M,N 为袜子的数量, M M M 为小 Z 所提的询问的数量。
接下来一行包含 N N N 个正整数 C i C_i Ci,其中 C i C_i Ci 表示第 i i i 只袜子的颜色,相同的颜色用相同的数字表示。
再接下来 M M M 行,每行两个正整数 L L L, R R R 表示一个询问。
输出格式
包含 M M M 行,对于每个询问在一行中输出分数 A / B A/B A/B 表示从该询问的区间 [ L , R ] [L,R] [L,R] 中随机抽出两只袜子颜色相同的概率。
若该概率为 0 0 0 则输出 0 / 1 0/1 0/1,否则输出的 A / B A/B A/B 必须为最简分数。
数据范围
N
,
M
≤
50000
N,M≤50000
N,M≤50000,
1
≤
L
<
R
≤
N
1≤L<R≤N
1≤L<R≤N,
C
i
≤
N
C_i≤N
Ci≤N
输入样例:
6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6
输出样例:
2/5
0/1
1/1
4/15
思路
对查询进行分块,排序。对于每个分块内部的查询,第一次使用暴力计算,之后使用滑窗方法更新数值。
注意要用long long。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+10;
struct P{int l,r,up,down,ind;}ask[N];
int n,m,a[N],t,L[N],R[N];
bool cmp1(P a,P b){ return a.l<b.l; }
bool cmp2(P a,P b){ return a.r<b.r; }
bool cmp3(P a,P b){ return a.ind<b.ind; }
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++) scanf("%lld%lld",&ask[i].l,&ask[i].r),ask[i].ind=i;
t=sqrt(n);
for(int i=1;i<=t;i++){
L[i]=(i-1)*t+1;
R[i]=i*t;
}
if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
sort(ask+1,ask+1+m,cmp1);
for(int i=1;i<=t;i++) sort(ask+L[i],ask+R[i]+1,cmp2);
for(int i=1;i<=t;i++){
int tmp[N],ans=0;
memset(tmp,0,sizeof(tmp));
for(int j=ask[L[i]].l;j<=ask[L[i]].r;j++){
tmp[a[j]]++; ans+=(tmp[a[j]]-1);
}
ask[L[i]].up=ans;
ask[L[i]].down=(ask[L[i]].r-ask[L[i]].l+1)*(ask[L[i]].r-ask[L[i]].l)/2;
for(int j=L[i]+1;j<=R[i];j++){
if(ask[j].l>ask[j-1].l)
for(int k=ask[j-1].l;k<ask[j].l;k++){
tmp[a[k]]--; ans-=tmp[a[k]];
}
else
for(int k=ask[j-1].l-1;k>=ask[j].l;k--){
tmp[a[k]]++; ans+=(tmp[a[k]]-1);
}
for(int k=ask[j-1].r+1;k<=ask[j].r;k++){
tmp[a[k]]++; ans+=(tmp[a[k]]-1);
}
ask[j].up=ans; ask[j].down=(ask[j].r-ask[j].l+1)*(ask[j].r-ask[j].l)/2;
}
}
sort(ask+1,ask+m+1,cmp3);
for(int i=1;i<=m;i++){
int gcd=__gcd(ask[i].up,ask[i].down);
if(ask[i].up) ask[i].up/=gcd,ask[i].down/=gcd;
else ask[i].down=1;
printf("%lld/%lld\n",ask[i].up,ask[i].down);
}
}
代码简化
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+10;
struct P{int l,r,up,down,ind;}ask[N];
int n,m,a[N],t,L[N],R[N],tmp[N];
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++) scanf("%lld%lld",&ask[i].l,&ask[i].r),ask[i].ind=i;
t=sqrt(n);
for(int i=1;i<=t;i++) L[i]=(i-1)*t+1,R[i]=i*t;
if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
sort(ask+1,ask+1+m,[](P& a,P& b){return a.l<b.l;});
for(int i=1;i<=t;i++) sort(ask+L[i],ask+R[i]+1,[](P& a,P& b){return a.r<b.r;});
for(int i=1,l=1,r=0,ans=0;i<=t;i++) for(int j=L[i];j<=R[i];j++){
while(r<ask[j].r){ ans+=tmp[a[++r]],tmp[a[r]]++; }
while(l>ask[j].l){ ans+=tmp[a[--l]],tmp[a[l]]++; }
while(r>ask[j].r){ tmp[a[r]]--,ans-=tmp[a[r--]]; }
while(l<ask[j].l){ tmp[a[l]]--,ans-=tmp[a[l++]]; }
ask[j].up=ans,ask[j].down=(ask[j].r-ask[j].l+1)*(ask[j].r-ask[j].l)/2;
}
sort(ask+1,ask+m+1,[](P& a,P& b){return a.ind<b.ind;});
for(int i=1;i<=m;i++){
int gcd=__gcd(ask[i].up,ask[i].down);
if(ask[i].up) ask[i].up/=gcd,ask[i].down/=gcd;
else ask[i].down=1;
printf("%lld/%lld\n",ask[i].up,ask[i].down);
}
}