小Z的袜子 bzoj2038 莫队

来源:互联网 发布:淘宝千人千面原理 编辑:程序博客网 时间:2024/06/11 02:14

题目大意

进行区间询问[l,r],输出该区间内随机抽两次抽到相同颜色袜子的概率。

分析

反正我是觉得莫队算法真tm神奇。
本蒟蒻就不讲了,贴个链接吧 莫队
一开始理解错题目了。。。

code

#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<string>#include<algorithm>#include<stack>#include<queue>#include<vector> #define ll long long using namespace std;  const int maxn=100000+10;struct arr{    int l,r;    int id;    ll A;    ll B;}question[maxn];int belong[maxn];int a[maxn];int n,m;int block;ll GCD(ll a,ll b){    while(b^=a^=b^=a%=b);    return a;}bool cmp(arr a,arr b){    if (belong[a.l]<belong[b.l]) return 1;    else if ((belong[a.l]==belong[b.l])&&(belong[a.r]<belong[b.r])) return 1;    return 0;}bool CMP(arr a,arr b){    return a.id<b.id;}ll ans=0;ll sum[maxn];void revise(int x,int add){    ans-=sum[a[x]]*sum[a[x]];    sum[a[x]]+=add;    ans+=sum[a[x]]*sum[a[x]];}int main(){    scanf("%d%d",&n,&m);    block=sqrt(n);    memset(sum,0,sizeof(sum));    for (int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        belong[i]=i/block+1;    }    for (int i=1;i<=m;i++)    {        scanf("%d%d",&question[i].l,&question[i].r);        question[i].id=i;    }    sort(question+1,question+1+m,cmp);    int l=1,r=0;    for (int i=1;i<=m;i++)    {        while(l<question[i].l) revise(l,-1),l++;        while(l>question[i].l) revise(l-1,1),l--;        while(r<question[i].r) revise(r+1,1),r++;        while(r>question[i].r) revise(r,-1),r--;        if(question[i].l==question[i].r)        {            question[i].A=0;            question[i].B=1;            continue;        }        question[i].A=ans-(question[i].r-question[i].l+1);        question[i].B=1LL*(question[i].r-question[i].l+1)*(question[i].r-question[i].l);        ll gcd=GCD(question[i].A,question[i].B);        question[i].A=question[i].A/gcd;        question[i].B=question[i].B/gcd;    }    sort(question+1,question+1+m,CMP);    for (int i=1;i<=m;i++)    {        printf("%lld",question[i].A);        printf("/");        printf("%lld\n",question[i].B);    }}
原创粉丝点击