P1494 [国家集训队]小Z的袜子(莫队)
题目链接:https://www.luogu.org/problemnew/show/P1494
题目大意:中文题目
具体思路:计算概率的时候,每一次是区间的移动,每一次移动,记得先将原来的记录的影响去掉,然后再加上新的值,每一次这样统计就可以了。然后计算概率的时候就是C(n,2),总的概率的计算方法,当前的颜色是的个数是t,然后就是C(t,2)。总的概率就是C(r-l+1,2),这里的r-l+1指的是当前要求的区间的长度。所以,合法的区间就是C(t,2)/C(r-l+1,2).
注意特判l==r的情况。
注意在减去原来的值的影响的时候,不能特判当前的值是不是大于2的,打个比方,原来的当前的值出现的是两次,我们先减去1,然后当前的值变成了1,这个时候我们按道理是需要将原来的影响给删掉,如果特判是不是大于等于2的话,就不可能减去了。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<cstring> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<cmath> 7 #include<algorithm> 8 #include<vector> 9 using namespace std; 10 # define ll long long 11 const int maxn = 2e5+100; 12 ll a[maxn],vis[maxn]; 13 struct node{ 14 ll l,r,pos,id; 15 bool friend operator < (node t1,node t2){ 16 if(t1.pos==t2.pos)return t1.r<t2.r; 17 return t1.pos<t2.pos; 18 } 19 }q[maxn]; 20 struct qq{ 21 ll t1,t2; 22 }ans[maxn]; 23 int main(){ 24 // freopen("hqx.in","r",stdin); 25 ll n,m; 26 scanf("%lld %lld",&n,&m); 27 ll block=(ll)sqrt(n); 28 for(ll i=1;i<=n;i++){ 29 scanf("%lld",&a[i]); 30 } 31 for(ll i=1;i<=m;i++){ 32 scanf("%lld %lld",&q[i].l,&q[i].r); 33 q[i].id=i; 34 q[i].pos=(q[i].l-1)/block+1; 35 } 36 sort(q+1,q+m+1); 37 ll tmp=0; 38 ll l=1,r=0; 39 for(ll i=1;i<=m;i++){ 40 while(l<q[i].l){vis[a[l]]--; 41 tmp-=(vis[a[l]]+1)*vis[a[l]]; 42 tmp+=vis[a[l]]*(vis[a[l]]-1); 43 l++; 44 } 45 while(l>q[i].l){l--;vis[a[l]]++; 46 tmp-=(vis[a[l]]-1)*(vis[a[l]]-2); 47 tmp+=vis[a[l]]*(vis[a[l]]-1); 48 } 49 while(r<q[i].r){ 50 r++;vis[a[r]]++; 51 tmp-=(vis[a[r]]-1)*(vis[a[r]]-2); 52 tmp+=vis[a[r]]*(vis[a[r]]-1); 53 } 54 while(r>q[i].r){ 55 vis[a[r]]--; 56 tmp-=(vis[a[r]]+1)*(vis[a[r]]); 57 tmp+=(vis[a[r]]*(vis[a[r]]-1)); 58 r--; 59 } 60 if(q[i].l==q[i].r){ 61 ans[q[i].id].t1=0; 62 ans[q[i].id].t2=1; 63 continue; 64 } 65 ans[q[i].id].t1=tmp; 66 ans[q[i].id].t2=(q[i].r-q[i].l+1)*(q[i].r-q[i].l); 67 } 68 for(ll i=1;i<=m;i++){ 69 ll tmp=__gcd(ans[i].t1,ans[i].t2); 70 if(ans[i].t1/tmp>ans[i].t2/tmp)printf("1/1\n"); 71 else 72 printf("%lld/%lld\n",ans[i].t1/tmp,ans[i].t2/tmp); 73 } 74 return 0; 75 }