问题描述
wld有n个数(a1...an)
保证对于任意$1 \leq i \leq n,1 \leq ai \leq n$
wld有一个常数k保证2 \leq k\leq 2*n2≤k≤2∗n
为了消除歧义保证k为奇数
他有mm个询问
每个询问有参数l1,r1,l2,r2l1,r1,l2,r2
保证(1 \leq l1\leq r1 < l2 \leq r2 \leq n)(1≤l1≤r1<l2≤r2≤n)
对于每个询问你需要回答有多少个二元组$(i,j)$满足:
l1 \leq i\leq r1l1≤i≤r1且l2 \leq j \leq r2l2≤j≤r2且ai + aj = kai+aj=k
保证1 \leq n\leq 30000, 1 \leq m \leq 300001≤n≤30000,1≤m≤30000
输入描述
多组数据(最多55组)
对于每组数据:
第一行:一个数nn表示数的个数
接下来一行:一个数kk表示wld的常数
接下来一行:nn个数,依次为$a1, a2, … an$
接下来一行:一个数mm表示询问数
接下来mm行:四个数l1, r1, l2, r2l1,r1,l2,r2表示这组询问的参数
输出描述
对于每组数据:
对于每个询问输出二元组的数目
输入样例
5
3
1 2 1 2 3
1
1 2 3 5
输出样例
2
Hint
a1 + a4 = 3
a2 + a3 = 3
思路:序列莫队加上容斥定理
设f(x,y)为区间[x,y]满足a[x]+a[y]=k的个数,则f(l1,r1,l2,r2)=f(l1,r2)-f(r1+1,r2)-f(l1,l2-1)+f(r1+1,l2-1);
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 30005;
const int blocksize = 200;
struct node
{
int left, right, id, p;
void init(int l1, int r1, int id1, int p1)
{
left = l1, right = r1;
id = id1, p = p1;
}
}query[4 * maxn];
bool cmp(node &a, node &b)
{
if (a.left / blocksize != b.left / blocksize) return a.left / blocksize < b.left / blocksize;
return a.right < b.right;
}
int cnt[2 * maxn], a[maxn], ans[maxn], n, k;
int main()
{
while (scanf("%d", &n) != EOF)
{
int cnt1 = 0;
scanf("%d", &k);
for (int i = 1;i <= n;i++)
scanf("%d", &a[i]);
memset(cnt, 0, sizeof(cnt));
memset(ans, 0, sizeof(ans));
int q;
scanf("%d", &q);
for (int i = 1;i <= q;i++)
{
int l1, r1, l2, r2;
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
query[cnt1++].init(l1, r2, i, 1);
query[cnt1++].init(r1 + 1, r2, i, -1);
query[cnt1++].init(l1, l2 - 1, i, -1);
if (r1 + 1 <= l2 - 1) query[cnt1++].init(r1 + 1, l2 - 1, i, 1);
}
sort(query, query + cnt1, cmp);
int left = 1, right = 0, res = 0;
for (int i = 0;i < cnt1;i++)
{
while (left > query[i].left)
{
left--;
if (k > a[left] && k - a[left] <= n)
res += cnt[k - a[left]];
cnt[a[left]]++;
}
while (right < query[i].right)
{
right++;
if (k > a[right] && k - a[right] <= n)
res += cnt[k - a[right]];
cnt[a[right]]++;
}
while (left < query[i].left)
{
cnt[a[left]]--;
if (k > a[left] && k - a[left] <= n)
res -= cnt[k - a[left]];
left++;
}
while (right > query[i].right)
{
cnt[a[right]]--;
if (k > a[right] && k - a[right] <= n)
res -= cnt[k - a[right]];
right--;
}
ans[query[i].id] += res*query[i].p;
}
for (int i = 1;i <= q;i++)
printf("%d\n", ans[i]);
}
return 0;
}