Codeforces Round 932 (Div. 2) D. Exam in MAC【正难则反+容斥原理】

原题链接:https://codeforces.com/problemset/problem/1935/D

题目描述:

硕士生援助中心公布了入学考试,考试内容如下。

给考生一个大小为 n 的集合 s 和一个奇怪的整数 c 。对于这个集合,需要计算出使 0≤x≤y≤c, x+y 包含在集合 s 中,并且 y−x也 包含在集合 s 中的整数对(x,y)的数目。

你的朋友想进入中心工作。请帮助他通过考试!

输入

每个测试由多个测试用例组成。第一行包含一个整数 t ( 1≤t≤2⋅10^4 ) - 测试用例的个数。测试用例说明如下。

每个测试用例的第一行包含两个整数 n 和 c ( 1≤n≤3⋅10^5 , 1≤c≤10^9 )--集合的大小和奇异整数。

每个测试用例的第二行包含 n 个整数 s1,s2,...,sn ( 0≤s1<s2<...<sn≤c )--集合的元素。( 0≤s1<s2<...<sn≤c ) - 集合 s 的元素。

保证所有测试用例中 n 的总和不超过 3⋅10^5

输出

对于每个测试用例,输出一个整数 - 合适的整数对的数目。

bash 复制代码
input
8
3 3
1 2 3
1 179
57
4 6
0 3 5 6
1 1
1
5 10
0 2 4 8 10
5 10
1 3 5 7 9
4 10
2 4 6 7
3 1000000000
228 1337 998244353
output
3
16139
10
2
33
36
35
499999998999122959

解题思路:

首先如果直接计算x+y不属于s和y-x不属于s貌似不太好计算, 这个时候就可以考虑正难则反了,ans=cnt(x,y)-cnt(x+y)-cnt(y-x)+cnt(x+y,y-x),其中ans表示答案,

cnt(x,y)表示所有的整数对(x,y)的数目,由于0<=x<=y<=c,所有总共的整数对一共有(c+1)*(c+2)/2。

cnt(x+y)表示x+y属于s的整数对的数目,那么对于0<=x<=floor(si/2)的所有x都有一个对应的y满足要求,那么就有从floor(si/2)+1个满足要求的整数对,floor表示向下取整。

cnt(y-x)表示y-x属于s的整数对的数目,那么对于si<=y<=c的所有y都有一个对应的x满足要求,那么就有(c-si+1)个满足要求的整数对。

cnt(x+y,y-x)表示x+y和x-y都属于s的所有整数对(x,y),那么不妨设x+y=si,y-x=sj,那么x=(si-sj)/2,y=(si+sj)/2,由于x和y都要求是整数,根据上述俩个式子可以得出,也就是要求si和sj的奇偶性相同即可,假设s中有odd个奇数,有even个偶数,那么这种情况满足要求的整数对数目就是(odd)*(odd+1)/2+even*(even+1)/2。

至于上述计算公式为什么最后还要加上cnt(x+y,y-x),这是因为容斥原理,我们把x+y属于s的部分减掉一遍,然后又把y-x属于s的减掉一遍,就会把x+y和y-x同时属于s的部分减掉俩遍,所有这部分还要加上一次,也就是还要加上一个cnt(x+y,y-x)。
时间复杂度:O(n),n表示输入数组的长度。

空间复杂度:不考虑输入的数组,空间复杂度O(1)。

cpp代码如下:

cpp 复制代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int N = 3e5 + 10;
int T, n, c;
int s[N];

void solve()
{
    cin >> n >> c;
    for (int i = 1; i <= n; i++)
        cin >> s[i];
    LL ans = 1ll * (c + 1) * (c + 2) / 2; // 总共的的(x,y)整数对数目
    int odd = 0, even = 0;                // odd记录s中的奇数个数,even记录s中的偶数个数
    for (int i = 1; i <= n; i++)
    {
        ans -= s[i] / 2 + 1; // cnt(x+y)
        ans -= c - s[i] + 1; // cnt(y-x)
        if (s[i] % 2 == 0)
            even++;
        else
            odd++;
    }
    // cnt(x+y,y-x)
    ans += 1ll * (even + 1) * (even) / 2;
    ans += 1ll * (odd + 1) * (odd) / 2;
    cout << ans << '\n';
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}
相关推荐
Gyoku Mint3 分钟前
机器学习×第五卷:线性回归入门——她不再模仿,而开始试着理解你
人工智能·python·算法·机器学习·pycharm·回归·线性回归
蒙奇D索大37 分钟前
【数据结构】图论最短路径算法深度解析:从BFS基础到全算法综述
数据结构·算法·图论·广度优先·图搜索算法
trouvaille38 分钟前
哈希数据结构的增强
算法·go
我不是小upper1 小时前
L1和L2核心区别 !!--part 2
人工智能·深度学习·算法·机器学习
liujing102329292 小时前
Day09_刷题niuke20250609
java·c++·算法
不7夜宵2 小时前
力扣热题100 k个一组反转链表题解
算法·leetcode·链表
蒟蒻小袁3 小时前
力扣面试150题--课程表
算法·leetcode·面试
闻缺陷则喜何志丹3 小时前
【动态规划】B4336 [中山市赛 2023] 永别|普及+
c++·算法·动态规划·洛谷
不二狗4 小时前
每日算法 -【Swift 算法】电话号码字母组合
开发语言·算法·swift
AL流云。4 小时前
【优选算法】分治
数据结构·算法·leetcode·排序算法