首页 写随笔

cdcq(本博客废弃!现用博客:https://www.cnblogs.com/cdcq/)

本博客废弃!现用博客:https://www.cnblogs.com/cdcq/

导航

【BZOJ2038】小Z的袜子

似乎是莫队提出莫队的题目?
原题:
作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……
具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。
你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。

N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

 

恩莫队裸题,分块排序什么的就不说了,关键在于O(1)转移答案

用的比较多的方法是每种颜色重复数平方的和减去区间长度为分子,区间长度*(区间长度-1)为分母(最后gcd搞一下)

我想不明白问什么,求教数学大神syq,syq大神太神辣

首先先直接写出公式,设第i种颜色重复数为a[i],左端点l,右端点r,则答案为( a[i]*(a[i]-1)+a[i+1]*(a[i+1]-1)+…… )/(r-l+1)*(r-l)

整理分子可以得到(a[i]*a[i] + a[i+1]*a[i+1]+……-a[i]-a[i+1]-……)

所有a的总和等于区间长度,-a[i]-a[i+1]-……就可以写成-(r-l+1)

所以最终答案表示为( a[i]*a[i] + a[i+1]*a[i+1]+……-(r-l+1) )/(r-l+1)*(r-l)

每次l和r左右移动的时候维护a[i]*a[i]的和即可

果然遇到数学相关还是要尝试推一下吗,一个思路是将复杂的其它量整合成简单的已知量?

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<vector>
 7 using namespace std;
 8 #define ll long long
 9 int rd(){int z=0,mk=1;  char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
11     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
12     return z*mk;
13 }
14 ll gcd(ll x,ll y){  return y?gcd(y,x%y):x;}
15 inline ll sqr(ll x){  return x*x;}
16 struct dcd{int l,r,id;}b[51000];
17 int n,m,a[51000];  int blck;
18 int cnt[51000];
19 ll bwl=0,x[51000],y[51000];
20 inline void mdf(int x,int y){  bwl-=sqr(cnt[a[x]]),cnt[a[x]]+=y,bwl+=sqr(cnt[a[x]]);}
21 bool cmp(dcd x,dcd y){  return (x.l/blck==y.l/blck)?(x.r<y.r):(x.l/blck<y.l/blck);}
22 int main(){//freopen("ddd.in","r",stdin);
23     cin>>n>>m;  blck=(int)sqrt(n*1.0);
24     for(int i=1;i<=n;++i)  a[i]=rd();
25     for(int i=1;i<=m;++i)  b[i].l=rd(),b[i].r=rd(),b[i].id=i;
26     sort(b+1,b+m+1,cmp);
27     int l=1,r=0;
28     for(int i=1;i<=m;++i){
29         while(l<b[i].l)  mdf(l,-1),++l;
30         while(l>b[i].l)  mdf(l-1,1),--l;
31         while(r<b[i].r)  mdf(++r,1);
32         while(r>b[i].r)  mdf(r--,-1);
33         x[b[i].id]=bwl-(b[i].r-b[i].l+1);
34         y[b[i].id]=(ll)(b[i].r-b[i].l+1)*(b[i].r-b[i].l);
35         int ggcd=gcd(x[b[i].id],y[b[i].id]);
36         x[b[i].id]/=ggcd,y[b[i].id]/=ggcd;
37     }
38     for(int i=1;i<=m;++i)  printf("%lld/%lld\n",x[i],y[i]);
39     return 0;
40 }
View Code

 

posted on 2017-02-22 09:03  cdcq_old  阅读(209)  评论(0编辑  收藏  举报