AtCoder题解——AtCoder Regular Contest 107——B - Quadruple

题目相关

题目链接

AtCoder Regular Contest 107 B 题,https://atcoder.jp/contests/arc107/tasks/arc107_b

Problem Statement

Given are integers N and K. How many quadruples of integers (a,b,c,d) satisfy both of the following conditions?

  • 1 ≤ a,b,c,d ≤ N
  • a+b−c−d=K

Input

Input is given from Standard Input in the following format:

N K

Output

Print the answer.

Samples1

Sample Input 1

2 1

Sample Output 1

4

Explaination

Four quadruples below satisfy the conditions:

  • (a,b,c,d)=(2,1,1,1)
  • (a,b,c,d)=(1,2,1,1)
  • (a,b,c,d)=(2,2,2,1)
  • (a,b,c,d)=(2,2,1,2)

Samples2

Sample Input 2

2525 -425

Sample Output 2

10314607400

Constraints

  • 1≤N≤10^5
  • −2(N−1)≤K≤2(N−1)
  • All numbers in input are integers.

题解报告

题目翻译

给定两个整数 N 和 K,在 1 ~ N 中,有几个四元组 (a, b, c, d) 满足 a+b-c-d=K。

题目分析

首先不要被四元组给迷惑,题目只是要求求出数量,而不是找出所有的四元组。因此本题核心还是一个纯数学问题。

任何一个题目,我们都可以先考虑暴力枚举。由于数据的最大值为 10^5,使用暴力枚举四元组 (a, b, c, d) ,对应的时间复杂度就是 O(N^4)。即使简单优化,变成暴力枚举三元组,时间复杂度也是 O(N^3)。意味着最大可能需要计算 10^5*10^5*10^5=10^{15},这肯定是一个 TLE 算法。

简化成为二元组

题目给出一个四元组计算,我们考虑一个简化版本,也就是两元组计算。即满足 a+b=K。或者量化看,a=9、b=7 和 k=13。我们可以枚举 a,通过 b=k-a 来计算 b。也就是说,我们只需要枚举以下可能两元组:

(1, k-1)
(2, k-2)
.
.
.
(k-2, 2)
(k-1, 1)

统计这些两元组中有几个可能存在就可以得到答案。这样就是一个 O(N) 的算法。

为什么是从 1 开始枚举呢?题目告诉我们 1\leq a\leq N

四元组问题

通过上面的描述,我们可以将四元组转换为二元组,也就是将 a+b 看成一个数,c+d 看成另外一个数,这样 a+b-c-d=k 的问题,就可以转化成为一个二元组问题。

根据题目给出的数据,我们知道 1 ≤ a,b,c,d ≤ N,也就意味着 2 ≤ a+b, c+d ≤ 2*N。这样问题就化简为一个 O(N) 级别。

数据分析

由于在计算中,需要使用到乘法原理,最大数据可能是 10^5*10^5=10^{10},必须使用 long long 这个数据类型表示。

AC 参考代码

//https://atcoder.jp/contests/arc107/tasks/arc107_b
//B - Quadruple 

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

LL n,k;

LL solve(LL sum) {
    LL tot = sum-1;
    LL sub = max(0LL, sum-n-1);
    return max(0LL, tot-2*sub);
}

int main() {
    cin>>n>>k;

    LL ans=0;
    for (LL i=k; i<=2*n; i++) {
        ans += (solve(i)*solve(i-k));
    }
    cout<<ans<<"\n";

    return 0;
}

代码细节

可能有人要问 max() 这个函数。

首先、max() 出自 STL 的 algorithm 库。

其次、max() 只能比较相同数据类型,所以使用 0LL 这个小技巧。表示这是一个 long long 的 0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值