zoukankan      html  css  js  c++  java
  • P1494 [国家集训队]小Z的袜子

    题目描述

    作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……

    具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。

    你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。

    然而数据中有L=R的情况,请特判这种情况,输出0/1。

    输入输出格式

    输入格式:

    输入文件第一行包含两个正整数N和M。N为袜子的数量,M为小Z所提的询问的数量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。

    输出格式:

    包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。(详见样例)

    输入输出样例

    输入样例#1: 
    6 4
    1 2 3 3 3 2
    2 6
    1 3
    3 5
    1 6
    输出样例#1: 
    2/5
    0/1
    1/1
    4/15

    说明

    30%的数据中 N,M ≤ 5000;

    60%的数据中 N,M ≤ 25000;

    100%的数据中 N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

    Solution:

      用这道题当作莫队的模板吧。(我这里不详细深究莫队的原理,只谈及一下自己的理解)莫队

      莫队其实就是优化的暴力。其实只有4个$while$循环,复杂度就体现在这4个循环的指针移动次数,而将进行分块并块内排序后能降低指针移动次数,起到优化作用。我们离线操作,读入查询的所有区间,分为$sqrt{n}$块,每块中按$r$升序排列。

      在每块中进行暴力指针移动,对于指针$l,r$各自只存在左移和右移两种情况,每次移动1步,便重新维护一下信息(本题中的分子),处理出答案后保存一下,最后输出就$OK$了。

      回到本题,我们设$s[i]$表示$i$数字在区间$[l,r]$中出现的次数,容易得出区间$[l,r]$的抽到概率为:

      $$frac{sum s[i]*(s[i-1]-1)}{(l-r+1)(l-r)}=frac{sum s[i]^2-sum s[i]}{(l-r+1)(l-r)}=frac{sum s[i]^2-(l-r+1)}{(l-r+1)(l-r)}$$

      于是我们只需维护一下$s[i]^2$,然后在每次指针移动后用分子减去原来的$s[i]^2$,更新$s[i]$,再加上新的$s[i]^2$,便求出新的分子,至于分母就是$(r-l+1)(r-l)$。

      然后求出分子和分母的最大公约数,约分一下并保存答案,最后输出就完美的解决了。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    using namespace std;
    const int N=50005;
    ll n,m,pos[N],a[N],ans,s[N],fen[N][2];
    struct data{
        ll l,r,id;
    }t[N];
    il ll gi()
    {
        ll a=0;char x=getchar();bool f=0;
        while((x<'0'||x>'9')&&x!='-')x=getchar();
        if(x=='-')x=getchar(),f=1;
        while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
        return f?-a:a;
    }
    il ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
    il bool cmp1(data a,data b){return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l;}
    il void add(ll p,ll val)
    {
        ans-=s[a[p]]*s[a[p]];
        s[a[p]]+=val;
        ans+=s[a[p]]*s[a[p]];
    }
    int main()
    {
        n=gi(),m=gi();
        for(int i=1;i<=n;i++)a[i]=gi();
        int ss=int(sqrt(n));
        for(int i=1;i<=n;i++)pos[i]=i/ss;
        for(int i=1;i<=m;i++)t[i].l=gi(),t[i].r=gi(),t[i].id=i;
        sort(t+1,t+1+m,cmp1);
        for(int i=1,l=1,r=0;i<=m;i++){
            while(r<t[i].r)r++,add(r,1);
            while(r>t[i].r)add(r,-1),r--;
            while(l<t[i].l)add(l,-1),l++;
            while(l>t[i].l)l--,add(l,1);
            if(t[i].l==t[i].r){fen[t[i].id][0]=0,fen[t[i].id][1]=1;continue;}
            fen[t[i].id][0]=ans-(t[i].r-t[i].l+1);
            fen[t[i].id][1]=(ll)(t[i].r-t[i].l+1)*(t[i].r-t[i].l);
            ll k=gcd(fen[t[i].id][0],fen[t[i].id][1]);
            fen[t[i].id][0]/=k,fen[t[i].id][1]/=k;
        }
        for(int i=1;i<=m;i++)printf("%lld/%lld
    ",fen[i][0],fen[i][1]);
        return 0;
    }

     

  • 相关阅读:
    设计模式之笔记--工厂方法模式(Factory Method)
    dmesg命令
    jumpserver2.3.0社区开源版
    container偶尔宕掉问题的解决记录
    sshd服务的白名单和黑名单
    /proc/sysrq-trigger文件
    ansible定义主机清单
    简述Etcd、Lvs、HAProxy
    ES6语法 let、const、for...of循环、展开运算符、ES6箭头函数、箭头函数和this、模板字面量、解构、对象字面量简写法、默认参数函数、super 和 extends、Object.assign()
    axios 将post请求时把对象obj数据转为formdata
  • 原文地址:https://www.cnblogs.com/five20/p/8781598.html
Copyright © 2011-2022 走看看