当前位置: 首页 > article >正文

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 

输出

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

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代码如下:

#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;
}

http://www.kler.cn/a/273962.html

相关文章:

  • (一)使用 WebGL 绘制一个简单的点和原理解析
  • 【Linux系列】并发与顺序执行:在 Linux 脚本中的应用与选择
  • C#开发——接口Interface
  • vue3中el-table实现多表头并表格合并行或列
  • 定时器PWM模拟DAC计算方法
  • 炸弹 (boom.c)
  • 【Unity】CatlikeCoding SRP
  • PHP反序列化--pop链
  • 手势追踪技术在HTC VIVE中的应用与实现
  • USART串口
  • 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级的理解
  • 二、yocto 集成ros2(基于raspberrypi 4B)
  • 【经验分享】Wubuntu------体验Windows和Ubuntu的结合体
  • VUE3 自定义指令
  • [游戏开发][Unity] 导出Xcode工程,完成调试与发布
  • KKVIEW远程: TODESK退出了还能远程吗
  • 【C++】手撕AVL树
  • Python库Gym:打开机器学习与强化学习的大门
  • 深入解析分布式ID生成机制
  • OpenAI 的 GPTs 提示词泄露攻击与防护实战:防御卷(二)
  • Another git process seems to be running in this repository, e.g. an editor o
  • 连接数据,畅通协作!企业数字化管理再升级
  • java入门 -输入和输出
  • 体验OceanBase OBD V2.5.0 组件内扩容和组件变更
  • Apache Doris 2.0.6 版本正式发布
  • 谷歌的后量子密码学威胁模型