洛谷 P1494 [国家集训队]小Z的袜子 题解
题目:在此。
考虑贡献。
一段区间是 ( l , r ) (l,r) (l,r),那么总选择数是 C r − l + 1 2 C^2_{r-l+1} Cr−l+12。
设有 k k k个不同颜色,第 i i i个有 a i a_i ai次,那么这一个的贡献是 C a i 2 C_{a_i}^2 Cai2。
所以答案为 ∑ C a i 2 C r − l + 1 2 \frac {\sum C_{a_i}^2}{C_{r-l+1}^2} Cr−l+12∑Cai2。
莫队维护 C a i 2 C_{a_i}^2 Cai2。
具体,假设某种颜色原有 x x x次。多了一次,答案就多加了 x x x,因为这个新的要与原来的 x x x个匹配。现有 x x x次,少了一次,答案就要减去 x x x,因为原来的那个与剩下的都匹配了,要反悔。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,q,m,a[50005],cnt[50005],ans[50005][3],sum;
struct query{
ll x,l,r;
}b[50005];
bool cmp(query c,query d){
return c.l/m!=d.l/m?c.l<d.l:((c.l/m)&1?c.r<d.r:c.r>d.r);
}
void add(ll x){
sum+=cnt[a[x]];
cnt[a[x]]++;
}
void del(ll x){
cnt[a[x]]--;
sum-=cnt[a[x]];
}
ll C(ll x){
return x*(x-1)/2;
}
int main(){
scanf("%lld%lld",&n,&q);
m=sqrt(n);
for (ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for (ll i=1;i<=q;i++) scanf("%lld%lld",&b[i].l,&b[i].r),b[i].x=i;
sort(b+1,b+q+1,cmp);
ll le=1,ri=0;
for (ll i=1,l,r;i<=q;i++){
l=b[i].l,r=b[i].r;
while (le<l) del(le),le++;
while (ri>r) del(ri),ri--;
while (le>l) le--,add(le);
while (ri<r) ri++,add(ri);
ans[b[i].x][0]=sum;
ans[b[i].x][1]=C(r-l+1);
}
for (ll i=1;i<=q;i++){
if (ans[i][1]==0){
printf("0/1\n");
continue;
}
ll g=__gcd(ans[i][0],ans[i][1]);
if (g)ans[i][0]/=g;
if (g)ans[i][1]/=g;
printf("%lld/",ans[i][0]);
printf("%lld\n",ans[i][1]);
}
}