HDU - 5213 Lucky (莫队+容斥原理)

题链:https://vjudge.net/problem/HDU-5213

题意:求[L,R]和[U,V]区间中,有多少对 ax+ay==k ?其中 L<=x<=R,U<=y<=V。题目保证 L<=R<U<=V.

思路:容斥原理,设sum(l,r)代表有[L,R]中有sum(l,r)对ax+ay==k,l<=x<y<=r.那么,答案为sum(l,v)-sum(l,u-1)-sum(r+1,v)+sum(r+1,u-1)。每个询问拆成4个询问,莫队一下即可。

(PS:太菜了,太菜了,太菜了,忘记去端点了。坤坤牛逼。)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e4+10;
int n,m,k;
int a[N];
struct node{
	int l,r,id;
	node(){}
	node(int l,int r,int id):l(l),r(r),id(id){}
}q[N<<2];
int num[N<<1];
int block,be[N];
bool cmp(node a,node b){
	return (be[a.l]^be[b.l]) ? be[a.l]<be[b.l] : (be[a.l]&1) ? a.r<b.r : a.r>b.r; 
}
bool cmp1(node a,node b){
	return a.id<b.id;
}
int sum,ans[N<<2];
void add(int x){
	if(k>=a[x])
		sum+=num[k-a[x]];		
	num[a[x]]++;
}
void del(int x){
	num[a[x]]--;
	if(k>=a[x])
		sum-=num[k-a[x]];
}
int main(void){
	while(~scanf("%d",&n)){
		scanf("%d",&k);
		block=ceil(sqrt(1.0*n));
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			be[i]=i/block;
			num[i]=num[i+n]=0;
		}
		scanf("%d",&m);
		int cnt=0;
		for(int i=1;i<=m;i++){
			int l,r,u,v;
			scanf("%d%d%d%d",&l,&r,&u,&v);
			q[++cnt]=node(l,v,cnt);
			q[++cnt]=node(r+1,u-1,cnt);
			q[++cnt]=node(l,u-1,cnt);
			q[++cnt]=node(r+1,v,cnt);			
		}
		sort(q+1,q+1+cnt,cmp);
		int l=1,r=0;
		sum=0;
		for(int i=1;i<=cnt;i++){
			int ql=q[i].l,qr=q[i].r;
			while(l<ql) del(l++);
			while(l>ql) add(--l);
			while(r<qr) add(++r);
			while(r>qr) del(r--);			
			ans[q[i].id]=sum;
		}
		sort(q+1,q+1+cnt,cmp1);
		for(int i=1;i<=cnt;i+=4)
			printf("%d\n",ans[i]+ans[i+1]-ans[i+2]-ans[i+3]);
	}
	
	return 0;	
} 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值