HDU - 5213 Lucky 莫队+容斥

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

题意:从两个区间中各拿一个数,和为k的选法

题解:容斥一下即为:sum[l, v]  - sum[l, u-1] - sum[r+1, v]  + sum[r+1, u-1]          sum[l, r] 表示从[l,r]中选择两个数和为k的选法, 剩下的就莫队分块解决一下就可以了

#include<bits/stdc++.h>
using namespace std;
const int N=30010;
int CM;
struct node{
	int id;
	int l,r;
	int val;
	bool operator <(const node &x)const
	{
		if(l/CM != x.l/CM) return l/CM < x.l/CM;
		else return r<x.r;
	}
}q[N*4];
int n,k,m;
int a[N],len;
int ans[N],num[N*2];
void add(int l,int r,int val,int id)
{
	len++;
	q[len].l=l;
	q[len].r=r;
	q[len].val=val;
	q[len].id=id;	
} 
int main()
{
	int l1,l2,r1,r2;
	int l,r,res;
	while(~scanf("%d",&n))
	{
		CM=(int)sqrt(n);
		scanf("%d",&k);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		scanf("%d",&m);
		len=0;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
			add(l1,r2,1,i);
			if(l1<=l2-1) add(l1,l2-1,-1,i);
			if(r2>=r1+1) add(r1+1,r2,-1,i);
			if(l2-1>=r1+1) add(r1+1,l2-1,1,i);
			
			ans[i]=0;
		}
		sort(q+1,q+1+len);
		for(int i=1,j=1;j<=len;i++)
		{
			l=q[j].l+1,r=q[j].l;
			res=0;
			for(int k=0;k<=n*2;k++)num[k]=0;
			for(;j<=len && j<i*CM;j++)
			{
				while(l<q[j].l)
				{
					res-=num[max(0,k-a[l])];
					num[a[l]]--;
					l++;
				}
				while(l>q[j].l)
				{
					l--;
					num[a[l]]++;
					res+=num[max(0,k-a[l])];
				}
				while(r<q[j].r)
				{
					r++;
					num[a[r]]++;
					res+=num[max(0,k-a[r])];
				}
				while(r>q[j].r)
				{
					res-=num[max(0,k-a[r])];
					num[a[r]]--;
					r--;
				}
			//	cout<<res<<" "<<q[j].l<<" "<<q[j].r<<endl;
				ans[q[j].id]+=res*q[j].val; 
			}
		}
		for(int i=1;i<=m;i++)
			printf("%d\n",ans[i]);
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值