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


    题目大意

    莫队入门题

    序列中有(n)个数

    (m)个询问,每次询问在区间([l,r])中,随机取两个数,数值相同的概率

    (1 leq n,m leq 50000)

    解题思路

    既然是莫队入门题,当然要用莫队做

    常规操作:对询问排序!

    排序就不多说,重点在指针移动时对答案的贡献

    首先,令(cnt[i])表示区间([l,r])中数值为(i)的个数

    那么我们很容易推出公式:

    [ans=frac{sum_{i=0}^{n}C(cnt_i,2)}{C(r-l+1,2)} ]

    设增加一个颜色(P)(右指针右移一格或左指针左移一格),

    那么分子变化量

    [egin{align} Delta &=C(cnt_P+1,2)-C(cnt_P,2) \ &=cnt_P end{align}]

    分母变化量

    [egin{align} Delta &=C(r-l+2,2)-C(r-l+1,2) \ &=r-l+1 end{align}]

    于是指针移动时可以(O(1))转移分子和分母

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    
    int n,m;
    
    int read(){
    	char ch;while (isspace(ch=getchar()));
    	int ret=ch&15;
    	while (isdigit(ch=getchar())) ret=(ret<<1)+(ret<<3)+(ch&15);
    	return ret;
    }
    
    struct node{
    	int col,inK;
    }T[100000];
    
    struct query{
    	int l,r;
    	int id;
    	bool operator < (const query &P) const {return T[l].inK<T[P.l].inK||T[l].inK==T[P.l].inK&&r<P.r;}
    }Q[100000];
    
    int sqrt(long long k){
    	long long l=0,r=k,mdl;
    	while (l<r){
    		mdl=(l+r+1)>>1;
    		if (mdl*mdl<=k) l=mdl;
    		else r=mdl-1;
    	}
    	return l;
    }
    
    long long gcd(long long a,long long b){return (!b)?a:(gcd(b,a%b));}
    
    int blo;
    
    int cnt[100000],x,y,l=1,r=0;
    
    std::pair<int,int> ans[100000];
    
    int main(){
    	n=read();m=read();
    	for (int i=1;i<=n;i++) T[i].col=read();
    	blo=sqrt(n);
    	for (int i=1;i<=blo;i++){
    		int L=n*(i-1)/blo+1,R=n*i/blo;
    		for (int j=L;j<=R;j++) T[j].inK=i;
    	}
    	for (int i=1;i<=m;i++){
    		Q[i].l=read(),Q[i].r=read();
    		Q[i].id=i;
    	}
    	std::sort(Q+1,Q+m+1);
    	for (int i=1;i<=m;i++){
    		while (l<Q[i].l){cnt[T[l].col]--;x-=cnt[T[l].col];y-=(r-l);l++;}
    		while (r>Q[i].r){cnt[T[r].col]--;x-=cnt[T[r].col];y-=(r-l);r--;}
    		while (l>Q[i].l){l--;x+=cnt[T[l].col];y+=r-l;cnt[T[l].col]++;}
    		while (r<Q[i].r){r++;x+=cnt[T[r].col];y+=r-l;cnt[T[r].col]++;}
    		if (l==r) ans[Q[i].id]=std::make_pair(0,1);
    		else{
    			int d=gcd(x,y);
    			ans[Q[i].id]=std::make_pair(x/d,y/d);
    		}
    	}
    	for (int i=1;i<=m;i++) printf("%d/%d
    ",ans[i].first,ans[i].second);
    }
    
  • 相关阅读:
    emWin模拟器Visual Studio开发时无法printf打印的问题
    双边滤波算法
    hough变换算法
    OpenCV3入门(十四)图像特效—挤压、哈哈镜、扭曲
    Canny检测算法与实现
    图像频域滤波与傅里叶变换
    OpenCV3入门(十二)角点检测
    OpenCV3入门(十一)图像直方图
    OpenCV3入门(十)图像轮廓
    一款基于SVM算法的分布式法律助手
  • 原文地址:https://www.cnblogs.com/ytxytx/p/9458525.html
Copyright © 2020-2023  润新知