洛谷P1494 【[国家集训队]小Z的袜子】

本文分享了一次使用莫队算法解决省选题的经历,详细介绍了算法的实现过程,包括组合数计算、莫队分块技巧及特判处理,适合初学者理解和实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

纪念自己独立完成的一道省选题(菜鸡如我只会看题解qwq)
还算是一道比较裸的莫队题把,比有的题目简单很多,也很好想怎么O(1)转移,比别的题就多了一个组合数计算(还有gcd??),还没算%意义下,也是很良心了

int get(int x){
	if(x<=1)return 0;
	return (int)(1.0*x*(x-1)*1.0/2.0);
}

直接获得当前的可能情况。
然后就是莫队的一套全家桶模板了。话说,莫队分块真的很玄学!
对了 题目还贴心的提示了特判问题 luogu不要太好。。!~~
这几天写了一些莫队题。莫队入门的话还是去写那些区间不重复数个数把,应该是最简单的题了(如果不卡莫队的话)然后对转移的add,del函数自己要推一下,然后套个全家桶就完事了

#include<bits/stdc++.h>
#define swap(a,b) {a^=b;b^=a;a^=b}
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define PII pair<int,int>
#define yxdl(qt) priority_queue<int,vector<int>,greater<int> >qt
#define xgd(qt)  priority_queue<int,vector<int>,less<int> >qt
#define INF 0x3f3f3f3f
#define lowbit(x)  x & -x
#define cs(s) freopen(s,"r",stdin)
#define debug(x) printf(" case-->%d ",x );
using namespace std;
typedef long long ll;
const int maxn =50101;
int a[maxn],flag[maxn],n,m,div1,l=0,r,up,down;
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
int get(int x){
	if(x<=1)return 0;
	return (int)(1.0*x*(x-1)*1.0/2.0);
}
struct uzi
{
	int l,r,id;
	bool operator<(const uzi &a)const {
		return l/div1==a.l/div1?r<a.r:l<a.l;
	}
}p[maxn];
void del(int x){
	up-=get(flag[a[x]]);
	flag[a[x]]--;
	if(flag[a[x]]<=1)return;
	up+=get(flag[a[x]]);
}
void add(int x){
	up-=get(flag[a[x]]);
	flag[a[x]]++;
	up+=get(flag[a[x]]);
}
struct node
{
	int up,down;
}ans[maxn];
int main(){
	scanf("%d%d",&n,&m);
	rep(i,1,n)scanf("%d",&a[i]);
	div1=sqrt(n);
	rep(i,1,m){
		scanf("%d%d",&p[i].l,&p[i].r);
		p[i].id=i;
	}
	sort(p+1,p+1+m);
	int bj[maxn];
	int po=0;
	rep(i,1,m){
		if(p[i].l==p[i].r){ans[p[i].id].up=0;ans[p[i].id].down=1;bj[++po]=p[i].id;}
		else{
			while(l<p[i].l)del(l++);
			while(l>p[i].l)add(--l);
			while(r<p[i].r)add(++r);
			while(r>p[i].r)del(r--);
			ans[p[i].id].up=up;
			ans[p[i].id].down=get(r-l+1);
		}
	}
	rep(i,1,m){
		if(ans[i].up==0){puts("0/1");continue;}
		int qq=gcd(ans[i].up,ans[i].down);
		printf("%d/%d\n",ans[i].up/qq,ans[i].down/qq );
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值