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

在这里插入图片描述
问题:解决 q q q次询问,每次询问 [ L , R ] [L,R] [L,R]中有多少对 ( i , j ) , 满足 a i = = a j (i,j),满足a_i==a_j (i,j),满足ai==aj
先想点超时但是可以解决的方法:
对于每次询问,枚举 L < = i < = R L<=i<=R L<=i<=R中的元素,令 n u m [ i ] num[i] num[i] i i i元素出现的次数,显然这样的对数是 n u m [ i ] ∗ ( n u m [ i ] − 1 ) / 2 num[i]*(num[i]-1)/2 num[i](num[i]1)/2
注意下题目似乎是静态的,并不是动态的。也许可以利用这点.
然而并没有想出来,据说是一种叫莫队的算法。
学习完莫队,发现这是莫队的板子题,真是富有启发性。
利用查询区间之间的信息,进行信息合并,很美妙的一个算法.

/*
Tonight I wanna drown in an ocean of you
*/
#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9+7;
const int maxn = 1e6+5;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int mx;
struct Node{
	int l,r,id;
	bool operator < (const Node &rhs)const{
		if(l/mx!=rhs.l/mx) return l<rhs.l;
		if((l/mx)&1) return r < rhs.r;
		return r>rhs.r;
	}
};//询问序列
Node q[maxn];
ll sum = 0;int cnt[maxn];int a[maxn];
void add(int i){
	sum += cnt[i];
	cnt[i]++;
}
void del(int i){
	cnt[i]--;
	sum -= cnt[i];
}
ll gcd(ll a,ll b){
	if(!b) return a;
	return gcd(b,a%b);
}
ll ans1[maxn],ans2[maxn];
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n,m;cin>>n>>m;
	mx = n / sqrt(n*2/3);
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=0;i<m;i++) cin>>q[i].l>>q[i].r,q[i].id = i;
	sort(q,q+m);
	for(int i=0,l=1,r=0;i<m;i++){
		if(q[i].l==q[i].r){
			ans1[q[i].id] = 0,ans2[q[i].id] = 1;
			continue;
		}
		while(l>q[i].l) add(a[--l]);
		while(r<q[i].r) add(a[++r]);
		while(l<q[i].l) del(a[l++]);
		while(r>q[i].r) del(a[r--]);
		ans1[q[i].id] =  sum;      //分子
		ans2[q[i].id] =  1LL*(r-l+1)*(r-l)/2;   //分母
	}
	for(int i=0;i<m;i++){
		if(ans1[i]!=0){
			ll g = gcd(ans1[i],ans2[i]);
			ans1[i]/=g,ans2[i]/=g;
		}
		else ans2[i] = 1;
		cout<<ans1[i]<<"/"<<ans2[i]<<"\n";
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值