[洛谷P1494]小Z的袜子

题目大意:有n个袜子,m个询问,每个询问给一个区间[L,R],问他有多大的概率抽到两只颜色相同的袜子
题解:离线,按l所在块为第一关键字,r为第二关键字排序,然后莫队


C++ Code:

#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
    long long l,r,num;
}q[50100];
inline bool cmp(node a,node b){
    if (a.l/224==b.l/224)return a.r<b.r;
    return a.l<b.l;
}
long long gcd(long long a, long long b){
    if (b==0)return a;
    return gcd(b,a%b);
}
long long n,m,num[50100],cnt[50100],ans[50100][2];
int main() {
    scanf("%lld%lld",&n,&m);
    for (long long i=1;i<=n;i++)scanf("%lld",&num[i]);
    for (long long i=0;i<m;i++)scanf("%lld%lld",&q[i].l,&q[i].r),q[i].num=i+1;
    sort(q,q+m,cmp);
    long long l=1,r=1,now=0;
    cnt[num[1]]=1;
    for (long long i=0;i<m;i++) {
        while (r>q[i].r)now-=--cnt[num[r--]];
        while (r<q[i].r)now+=cnt[num[++r]]++;
        while (l<q[i].l)now-=--cnt[num[l++]];
        while (l>q[i].l)now+=cnt[num[--l]]++;
        ans[q[i].num][0]=now;ans[q[i].num][1]=q[i].r-q[i].l+1;
    }
    for (long long i=1;i<=m;i++) {
        long long tmp=ans[i][1]*(ans[i][1]-1)>>1,e=gcd(ans[i][0],tmp);
        if (!e)puts("0/1");
            else printf("%lld/%lld
",ans[i][0]/e,tmp/e);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Memory-of-winter/p/8728127.html