码迷,mamicode.com
首页 > 其他好文 > 详细

P1494 [国家集训队]小Z的袜子

时间:2018-04-10 19:42:47      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:sqrt   查询   输入   原理   print   mil   fun   存在   代码   

题目描述

作为一个生活散漫的人,小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)$。

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

 

代码:

 

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define debug printf("%d %s\n",__LINE__,__FUNCTION__)
 5 using namespace std;
 6 const int N=50005;
 7 ll n,m,pos[N],a[N],ans,s[N];
 8 struct data{
 9     ll a,b,l,r,id;
10 }t[N];
11 il ll gi()
12 {
13     ll a=0;char x=getchar();bool f=0;
14     while((x<0||x>9)&&x!=-)x=getchar();
15     if(x==-)x=getchar(),f=1;
16     while(x>=0&&x<=9)a=a*10+x-48,x=getchar();
17     return f?-a:a;
18 }
19 il ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
20 il bool cmp1(data a,data b){return pos[a.l]==pos[b.l]?a.r<b.r:pos[a.l]<pos[b.l];}
21 il bool cmp2(data a,data b){return a.id<b.id;}
22 il void add(ll p,ll val)
23 {
24     ans-=s[a[p]]*s[a[p]];
25     s[a[p]]+=val;
26     ans+=s[a[p]]*s[a[p]];
27 }
28 int main()
29 {
30     n=gi(),m=gi();
31     for(int i=1;i<=n;i++)a[i]=gi();
32     int ss=int(sqrt(n));
33     for(int i=1;i<=n;i++)pos[i]=(i-1)/ss+1;
34     for(int i=1;i<=m;i++)t[i].l=gi(),t[i].r=gi(),t[i].id=i;
35     sort(t+1,t+1+m,cmp1);
36     for(int i=1,l=1,r=0;i<=m;i++){
37         while(r<t[i].r)add(r+1,1),r++;
38         while(r>t[i].r)add(r,-1),r--;
39         while(l<t[i].l)add(l,-1),l++;
40         while(l>t[i].l)add(l-1,1),l--;
41         if(t[i].l==t[i].r){t[i].a=0,t[i].b=1;continue;}
42         t[i].a=ans-(t[i].r-t[i].l+1);
43         t[i].b=(ll)(t[i].r-t[i].l+1)*(t[i].r-t[i].l);
44         ll k=gcd(t[i].a,t[i].b);
45         t[i].a/=k;t[i].b/=k;
46     }
47     sort(t+1,t+m+1,cmp2);
48     for(int i=1;i<=m;i++)printf("%lld/%lld\n",t[i].a,t[i].b);
49     return 0;
50 }

 

 

 

 

P1494 [国家集训队]小Z的袜子

标签:sqrt   查询   输入   原理   print   mil   fun   存在   代码   

原文地址:https://www.cnblogs.com/five20/p/8781598.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!