HDU 5213 分块 容斥

给出n个数,给出m个询问,询问 区间[l,r] [u,v],在两个区间内分别取一个数,两个的和为k的对数数量。

$k<=2*N$,$n <= 30000$

发现可以容斥简化一个询问。一个询问的答案为 $[l,v]+(r,u)-[l,u)-(r,v]$,那么我们离线询问,将一个询问分成四个,分块暴力就行了。

然后就是注意细节,不要发生越界,访问错位置之类比较蠢的问题了。

/** @Date    : 2017-09-24 19:54:55
  * @FileName: HDU 5213 分块 容斥.cpp
  * @Platform: Windows
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5 + 20;
const double eps = 1e-8;

int a[30010];
int blc[30010];
struct yuu
{
	int l, r, idx, f;
	yuu() {}
	inline yuu(int _l, int _r, int i, int _f): l(_l), r(_r), idx(i), f(_f) {}
} b[120010];//明明是RE 报的TLE 有毒啊?
LL ans[30010];
LL vis[30010];

inline int cmp(yuu a, yuu b)
{
	if(blc[a.l] != blc[b.l])
		return a.l < b.l;
	return a.r < b.r;
}
int main()
{
	int n, k;
	while(~scanf("%d%d", &n, &k))
	{
		int sqr = sqrt(n * 1.0);
		for(int i = 1; i <= n; i++)
			scanf("%d", a + i), blc[i] = (i - 1) / sqr + 1;
		int m;
		scanf("%d", &m);
		for(int i = 0; i < m; i++)
		{
			int l, r, u, v;
			scanf("%d%d%d%d", &l, &r, &u, &v);
			b[i * 4] = yuu(l, v, i, 1);
			b[i * 4 + 1] = yuu(r + 1, u - 1, i, 1);
			b[i * 4 + 2] = yuu(l, u - 1, i, -1);
			b[i * 4 + 3] = yuu(r + 1, v, i, -1);
		}
		sort(b, b + m * 4, cmp);
		MMF(ans);
		MMF(vis);
		LL t = 0;
		int l = 1, r = 0;
		for(int i = 0; i < m * 4; i++)
		{
			while(r < b[i].r)
			{
				r++;
				vis[a[r]]++;
				if(k - a[r] > 0 && k - a[r] <= n)//小于n
					t += vis[k - a[r]];
			}
			while(l > b[i].l)
			{
				l--;
				vis[a[l]]++;
				if(k - a[l] > 0 && k - a[l] <= n)
					t += vis[k - a[l]];
			}
			while(r > b[i].r)
			{
				if(k - a[r] > 0 && k - a[r] <= n)
					t -= vis[k - a[r]];
				vis[a[r]]--;
				r--;
			}
			while(l < b[i].l)
			{
				if(k - a[l] > 0 && k - a[l] <= n)
					t -= vis[k - a[l]];
				vis[a[l]]--;
				l++;
			}
			ans[b[i].idx] += t * b[i].f;
			//cout << t << b[i].l << b[i].r << endl;
		}
		for(int i = 0; i < m; i++)
			printf("%lld\n", ans[i]);
	}
	return 0;
}
//
时间: 2024-10-17 17:42:08

HDU 5213 分块 容斥的相关文章

hdu 5514 Frogs(容斥)

Frogs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1315    Accepted Submission(s): 443 Problem Description There are m stones lying on a circle, and n frogs are jumping over them.The stones a

HDU 6053 TrickGCD 容斥

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6053 题意: 给你序列a,让你构造序列b,要求 1<=b[i]<=a[i],且b序列的gcd>=2.问你方案数. 思路: 容易想到的就是我们枚举整个序列的gcd,然后a[i]/gcd就是i位置能够填的数的个数,然后每个位置累积就能得到数列为gcd时的方案数. 最后容斥一下累加就是答案.但是最大gcd可以是100000和明显这样做n^2,会超时. 那么我们把a[i]/gcd的放在一起,然后用

hdu 5212 反向容斥或者莫比

http://acm.hdu.edu.cn/showproblem.php?pid=5212 题意:忽略.. 题解:把题目转化为求每个gcd的贡献.(http://www.cnblogs.com/z1141000271/p/7419717.html 和这题类似 反向容斥)这里先用容斥写了,mobious的之后再说吧23333. 然后比较想说的是这个调和级数的复杂度 nlog(n) ac代码: #include <iostream> #include <cstdio> #includ

JZYZOJ1518 [haoi2011]b 莫比乌斯反演 分块 容斥

http://172.20.6.3/Problem_Show.asp?id=1518最开始只想到了n^2的写法,肯定要超时的,所以要对求gcd的过程进行优化.首先是前缀和容斥,很好理解.第二个优化大致如下:u为莫比乌斯函数,t为gcd(x,y)为i的倍数的数的个数:满足gcd(x,y)=1的数字对的数量=sigma(1<=i<=min(x,y))u[i]*t[i];t[i]=(x/i)*(y-i);由小数向下取整可知有连续的i满足x/i为定值,y/i也是定值,所以可以分块计算,用u[i]的前缀

hdu 4407 Sum 容斥+离线

求X-Y之间和p互质的数的和,典型的容斥问题,求和用等差数列求和,注意首项末项是多少. 首先记录下不修改的答案,离线处理,存下询问,输出的时候,遇到一个操作1,就遍历前面的操作,把修改加上去,注意要判重,只保留最后一次修改. #include <stdio.h> #include <vector> #include <algorithm> #include <cmath> #include <iostream> #include<cstri

hdu 5514 Frogs 容斥思想+gcd 银牌题

Frogs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1509    Accepted Submission(s): 498 Problem Description There are m stones lying on a circle, and n frogs are jumping over them.The stones a

HDU 1695 GCD(容斥 or 莫比乌斯反演)

这题可以用容斥做,然而效率并不高.. 于是学了下莫比乌斯反演(资料百度找) 求出mo数组后 设f(x)为gcd为x的种数 F(x)为gcd为x倍数的种数 那么显然F(x) = (b / x) * (d / x) 莫比乌斯反演之后,得到f(x) = sum(mo[i] * F(i)). 然后还要容斥减去对称重复的.对称重复的情况为min(b, d)小的中,求一遍除2,(因为存在x = y的情况只有(1,1)一种) 最后还要注意特判下k == 0的情况 代码: #include <cstdio>

HDU 4135 Co-prime (容斥+分解质因子)

<题目链接> 题目大意: 给定区间[A,B](1 <= A <= B <= 10 15)和N(1 <=N <= 10 9),求出该区间中与N互质的数的个数. 解题分析: 将求区间[A,B]与N互质的数转化成求[1,B] 区间与N互质的个数  -  [1,A-1]中与N互质的个数.同时,因为直接求区间内与N互质的数不好求,我们从反面入手,求出与N不互质的数,借鉴埃筛的思想,我们先求出N的所有质因子,然后将这些质因子在区间内倍数的个数全部求出(即与N不互质的数),再用

hdu 4407 Sum(容斥)

http://acm.hdu.edu.cn/showproblem.php?pid=4407 起初有n个数1~n,这里有m个操作,两种类型.操作1:求出[x,y]区间内与p互质的数的和.操作2:将第x位置的数变成y.对于每一个询问,输出结果. 因为只有1000次操作,而且起初是有序的.那么对于第i个询问,我们先忽略i之前的所有的第2种操作,即认为n个数为1~n,根据容斥原理求出[x,y]区间内与p互质的数之和,然后遍历i之前的操作2,对所求的答案进行调整即可.wa了无数次,改了好久,是因为我忽略