洛谷P1494 [国家集训队]小Z的袜子(无修改莫队)

传送门
莫队入门题.
作为众多莫队难题里的一股清流.这题能很好的体现莫队的优雅.
莫队的复杂度证明过程和模板网上很多就不赘述了,说说add和del需要注意的地方.根据组合数学的知识我们可以知道,假设区间长度为len.那么拿到两个相同颜色的袜子的概率为:a1×(a1-1)/len×(len-1)+a2…+an…先考虑add.(a+1)*a展开就是a2+a.比原先a2-a加了2a那么多,del即是变成了a2-a-2a+2.比原先多了-2a+2.两个操作就结束了.
然后还有一点处理之后的询问顺序已经乱了,在处理区间长度为1的特殊情况时不能用当前询问的左右端点,直接用记录好的长度就行了.

#pragma GCC optimize(2)
#define LL long long
#define pll pair<LL,LL>
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define afir(i,a,b) for(int i=a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#include <bits/stdc++.h>

using namespace std;
const int N = 1e6+10;

inline int read(){
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
struct Q{
	int l,r,p;
}q[N];
int num,blo,n,m,L[N],R[N],pos[N];
LL a[N],cnt[N];
pll ans[N];
LL gcd(LL a,LL b){
	return b?gcd(b,a%b):a;
}
bool cmp(Q a,Q b){
	return pos[a.l]^pos[b.l]?pos[a.l] < pos[b.l]:(pos[a.l]&1)?a.r < b.r:a.r > b.r;
}
void build(){
	blo = sqrt(n);
	num = n/blo;
	fir(i,1,num){
		L[i] = (i-1)*blo+1;
		R[i] = i*blo;
	}
	if(n % blo){
		num++;
		L[num] = R[num-1]+1;
		R[num] = n;
	}
	fir(i,1,num){
		fir(j,L[i],R[i]){
			pos[j] = i;
		}
	}
}
LL cur = 0;
void add(int x){
	cur += 2*cnt[a[x]];
	cnt[a[x]]++;
}
void del(int x){
	cur += -2*cnt[a[x]] + 2;
	cnt[a[x]]--;
}
int main(){
	n = read();m = read();
	fir(i,1,n) a[i] = read();
	fir(i,1,m){
		q[i].l = read();
		q[i].r = read();
		q[i].p = i;
	}
	build();
	sort(q+1,q+1+m,cmp);
	int l=1,r=0;
	fir(i,1,m){
		while(q[i].l < l) add(--l);
		while(q[i].l > l) del(l++);
		while(q[i].r > r) add(++r);
		while(q[i].r < r) del(r--);
		ans[q[i].p] = make_pair(cur,q[i].r-q[i].l+1);
	}
	fir(i,1,m){
		if(ans[i].sd == 1 || !ans[i].ft) printf("0/1\n");
		else{
			LL g = gcd(ans[i].ft,ans[i].sd*(ans[i].sd-1));
			printf("%lld/%lld\n",ans[i].ft/g,1LL*ans[i].sd*(ans[i].sd-1)/g);
		}
	}
	
	return 0;
}	

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/106240997
今日推荐