• BZOJ 2038 小Z的袜子


    这是一道很经典的题目了,解法当然是莫队算法.

    推导过程我有空再写,那么先写一写结论.

    对于某个区间,小Z要求的概率为这个区间内所有颜色个数的平方和减去区间长度的差除以区间长度的平方减去区间长度的差

    记这些颜色的数目为$c_1,c_2,c_3,dots,c_n$,那么答案就是[frac{left(sumlimits_{i=1}^{n}c_i^2 ight)-(R-L+1)}{(R-L+1)cdot (R-L)}]

    这个结论很经典,非常经典.这个结论无法相加,也就是无法合并.但是它可以拓展,或者缩小自己的范围,而增加或减少一只袜子的信息都只要$O(1)$的时间.那么我们用某种方式给输入数据排个序,按顺序处理这些输入,显然,处理顺序不同所要的时间也就不同.

    首先思考如何做到$Oleft(n^2 ight)$.注意到我们只需要让其中的一个参数(比如$R$)单调递增就可以做到了.(如何证明自己想一想)那么我们将另一个参数分$sqrt{n}$块,那么块内的所有询问总复杂度就是$O(n)$了,因为总共有$O(sqrt{n})$块,那么总复杂度就是$O(nsqrt{n})$了.

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    typedef int INT;
    #define int unsigned int
    int gcd(int a,int b){
    	if(b) return gcd(b,a%b);
    	return a; 
    }
    inline int sqr(int a){return a*a;}
    struct upderr{
    	int l,r,colornum[60000],p;
    	inline void updadd(int c,int lc,int rc){
    		l-=lc,r+=rc;
    		p=p-sqr(colornum[c])+sqr(colornum[c]+1);
    		++colornum[c];
    	}
    	inline void updsub(int c,int lc,int rc){
    		l+=lc,r-=rc;
    		p=p-sqr(colornum[c])+sqr(colornum[c]-1);
    		--colornum[c];
    	}
    	inline void fetch(int& up,int& down){
    		down=r-l+1;
    		up=p-down;
    		down=down*(down-1);
    		int pp=gcd(up,down);
    		up/=pp,down/=pp;
    	}
    } upder;
    int pos[100000],i,sl,n,m,color[100000],ans[100000][2];
    struct query{
    	int l,r,id;
    	void performQuery(){
    		if(l==r) ans[id][0]=0,ans[id][1]=1; else{
    			while(upder.l>l){
    				upder.updadd(color[upder.l-1],1,0);
    			}
    			while(upder.r<r){
    				upder.updadd(color[upder.r+1],0,1);
    			}
    			while(upder.l<l){
    				upder.updsub(color[upder.l],1,0);
    			}
    			while(upder.r>r){
    				upder.updsub(color[upder.r],0,1);
    			}
    			upder.fetch(ans[id][0],ans[id][1]);
    		}
    	}
    } ies[100000];
    bool cmp(query a,query b){
    	if(pos[a.l]<pos[b.l]) return true;
    	if(pos[a.l]>pos[b.l]) return false;
    	return a.r<b.r;
    }
    INT main(){
    	freopen("littleZ.in","r",stdin);
    	freopen("littleZ.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	sl=round(sqrt(n));
    	for(i=1;i<=n;++i){
    		pos[i]=(i-1)/sl;
    	}
    	for(i=1;i<=n;++i) scanf("%d",color+i);
    	for(i=0;i<m;++i) scanf("%d%d",&ies[i].l,&ies[i].r),ies[i].id=i;
    	std::sort(ies,ies+m,cmp);
    	upder.l=upder.r=1;
    	upder.colornum[color[upder.l]]=1;
    	upder.p=1;
    	for(i=0;i<m;++i) ies[i].performQuery();
    	for(i=0;i<m;++i) printf("%d/%d
    ",ans[i][0],ans[i][1]);
    	return 0;
    }
    

    注意这题要用unsigned int,切记.

  • 相关阅读:
    《生命3.0—在亿年的尺度下审视生命的演进》阅读笔记3
    软件杯赛题周总结(2)
    《生命3.0—在亿年的尺度下审视生命的演进》阅读笔记2
    记一次阅读源码的小经历
    11
    解决在 CSS 中,如何实现动态吸顶的样式/效果 ?
    Angular 初始化项目后,如何把默认的 .css 文件修改为 .scss 文件?
    解决 Angular 项目中,添加 <router-outlet> 标签后,报错: ‘router-outlet’ is not a known element 的问题。
    在 Angular 项目中,如何为项目单独创建路由文件?
    [NOIP2013 提高组] 《火柴排队》
  • 原文地址:https://www.cnblogs.com/tmzbot/p/4461313.html
Copyright © 2020-2023  润新知