题目描述
作为一个生活散漫的人,小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 }
原文地址:https://www.cnblogs.com/five20/p/8781598.html