题解:Atcoder Beginner Contest abc467 A~D

A - Obesity

题目描述

用下面的公式计算出的数值叫做 \\mathrm{BMI}\[\\mathrm{kg}/\\mathrm{m}\^2\]

  • \\text{Weight}\[\\mathrm{kg}\] \\div \\text{Height}\[\\mathrm{m}\] \\div \\text{Height}\[\\mathrm{m}\]

在日本, \\mathrm{BMI} 大于或等于 25 \\; \\mathrm{kg}/\\mathrm{m}\^2 的人被视为肥胖。

请判断身高 H\[\\mathrm{cm}\] 、体重 W\[\\mathrm{kg}\] 的人在日本是否属于肥胖。

解题思路

A题不讲了。脑残题。

完整代码

复制代码
#include<bits/stdc++.h>
#define fr1(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define fr2(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define fv(i,p) for(auto (i):(p))
#define ll long long
#define ull unsigned ll
#define pii pair<int,int>
#define pll pair<ll,ll>
#define _1st first
#define _2nd second
#define elif else if
#define debug cout<<endl<<"-------------------------------------------------------------"<<endl
using namespace std;
int h,w; 
int main(){
	ios::sync_with_stdio(false);
	cin.tie(NULL);cout.tie(NULL);
	cin>>h>>w;
	if(400*w>=h*h){
       	cout<<"Yes";
    }else{
        cout<<"No";
    }
	return 0;
}

B - Keep the Change

题目描述

高桥在 N 家商店购物。最初,他有 10000 日元。

i th商店,他购买了价值 A_i 日元的商品,支付了 B_i 日元。这里, A_i \\leq B_i 成立。如果 S_i = keep ,他没有收到零钱;如果 S_i = take , A_i \\leq B_i 成立 ,他收到了零钱。

求与他在每家店都收到零钱的情况相比,他损失了多少钱。准确地说:

X 日元是高桥的最终金额,并且让 Y 日元成为高桥在每家店都收到零钱的情况下的最终金额。

求出 Y - X .

解题思路

最脑残的一次B题。

完整代码

复制代码
#include<bits/stdc++.h>
#define fr1(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define fr2(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define fv(i,p) for(auto (i):(p))
#define ll long long
#define ull unsigned ll
#define pii pair<int,int>
#define pll pair<ll,ll>
#define _1st first
#define _2nd second
#define elif else if
#define debug cout<<endl<<"-------------------------------------------------------------"<<endl
using namespace std;
int n,ans;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(NULL);cout.tie(NULL);
	cin>>n;
	fr1(i,1,n){
		int a,b;
		string s;
		cin>>a>>b>>s;
		if(s=="keep")ans+=b-a;
	}
	cout<<ans;
	return 0;
}

C - Adjacent Sums(简单版)

题目描述

C 题的题目描述与E题相同。只有加粗的数据范围不同。

给你一个整数序列 A=(A_1,A_2,\\dots,A_N),B=(B_1,B_2,\\dots,B_{N-1}) ,它由介于 0M-1 之间的整数组成。 AB 的长度分别为 NN-1

您可以对 A 执行以下操作任意多次。

  • 选择带有 1 \\leq i \\leq N 的整数 i ,将 1 加到 A_i 中。

求满足以下条件所需的最少运算次数。

可以证明,在本题的限制条件下,该条件总是可以满足的。

  • 对于 i=1,2,\\dots,N-1 来说, A_i+A_{i+1} 除以 M 的余数等于 B_i

数据范围

  • 2 \\leq N \\leq 2 \\times 10\^5
  • M=2
  • 0 \\leq A_i \\leq M-1
  • 0 \\leq B_i \\leq M-1
  • 所有输入值均为整数。

解题思路

数学转化(核心,M=2,模 2 等价异或)

模 2 加法等价于按位异或:

\((P+Q) \bmod 2 = P \oplus Q\) 把约束拆开:

\((A_i+x_i) \oplus (A_{i+1}+x_{i+1}) = B_i\) 移项变形(异或等式两边同时异或同一个数等式不变):

\(x_{i+1} = B_i \oplus A_i \oplus x_i \oplus A_{i+1}\) .

关键结论:整个序列 \(x_1,x_2,\dots,x_N\) 完全由 \(x_1\) 决定

  • 若确定 \(x_1\),用上面公式能依次算出 \(x_2,x_3,\dots,x_N\);
  • 因为 \(M=2\),\(x_1\) 在模 2 下只有两种可能:0 或 1;
  • 只需要枚举 \(x_1=0\)、\(x_1=1\) 两种情况,分别算出全套 x 数组的总代价 \(\sum x_i\),取最小值就是答案。

代价说明

为什么代价直接累加 \(x_i\)? \(x_i\) 是第 i 个元素一共加了多少次 1,每加 1 算一次操作,总操作次数就是所有 \(x_i\) 相加,和题目定义完全一致。

完整代码

复制代码
#include<bits/stdc++.h>
#define fr1(i,a,b) for(int(i)=(a);(i)<=(b);(i)++)
#define fr2(i,a,b) for(int(i)=(a);(i)>=(b);(i)--)
#define fv(i,p) for(auto (i):(p))
#define ll long long
#define ull unsigned ll
#define pii pair<int,int>
#define pll pair<ll,ll>
#define _1st first
#define _2nd second
#define elif else if
#define debug cout<<endl<<"-------------------------------------------------------------"<<endl
using namespace std;
int n,m;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);
    cin>>n>>m;
    vector<int>a(N+1),b(N);
    fr1(i,1,N)cin>>a[i];
    fr1(i,1,N-1)cin>>b[i];
    ll ans=LLONG_MAX;
    fr1(start,0,1){
        vector<int>x(n+1);
        x[1]=start;
        ll cost=x[1];
        fr1(i,1,n-1){
            x[i+1]=b[i]^a[i]^x[i]^a[i+1];
            cost+=x[i+1];
        }
        ans=min(ans,cost);
    }
    cout<<ans<<endl;
    return 0;
}

D - Concentric Circles

题目描述

xy \ 平面上是否存在满足以下所有条件的两个圆 C_1C_2 ?这里, C_1C_2 可能重合。

  • 两个不同的点 (P_x, P_y)(Q_x, Q_y) 位于 C_1 的圆周上。

  • 两个不同的点 (R_x, R_y)(S_x, S_y) 位于 C_2 的圆周上。

  • C_1C_2 具有相同的圆心。

给你 T 个测试用例,请逐一求解。

数据范围

  • 1 \\leq T \\leq 5 \\times 10\^4
  • -10\^9 \\leq P_x,P_y,Q_x,Q_y,R_x,R_y,S_x,S_y \\leq 10\^9
  • (P_x, P_y) \\neq (Q_x, Q_y)
  • (R_x, R_y) \\neq (S_x, S_y)
  • 所有输入值均为整数。

解题思路

一、几何前置结论:两点确定圆心的约束

若一个圆同时过两个不同点 \(A,B\),设圆心为 \(O(x_0,y_0)\),则:

\(|OA|^2 = |OB|^2\) 展开距离平方并化简:

\((x_0-A_x)^2+(y_0-A_y)^2 = (x_0-B_x)^2+(y_0-B_y)^2\) 消去 \(x_0^2,y_0^2\),整理得到一条直线方程

\(2(B_x-A_x)x_0 + 2(B_y-A_y)y_0 = B_x^2+B_y^2 - A_x^2-A_y^2\) 这条直线就是线段 AB 的垂直平分线

关键:所有能作为 "过 \(A,B\) 的圆的圆心" 的点,全部落在 AB 的垂直平分线上。

设:

  • \(L_1\):PQ 的垂直平分线(所有合法 \(C_1\) 圆心集合)
  • \(L_2\):RS 的垂直平分线(所有合法 \(C_2\) 圆心集合)

题目等价转化为:直线 \(L_1\) 和 \(L_2\) 是否存在交点

  • 若存在交点 O:以 O 为圆心,分别取 \(|OP|\)、\(|OR|\) 为半径作同心圆,满足全部条件,输出 Yes;
  • 若不存在交点(两直线平行且不重合):没有公共圆心,输出 No。

二、分两类讨论 \(L_1\) 与 \(L_2\) 的位置关系

两条直线只有两种位置:

  1. 不平行(相交);
  2. 平行(要么完全重合,要么无交点)。

情况 1:\(L_1\) 与 \(L_2\) 不平行 → 一定有交点 → 答案 Yes

两条直线不平行等价于:线段 PQ、RS 本身不平行。 线段平行判定:取向量 \(\overrightarrow{PQ}=(Q_x-P_x,Q_y-P_y)\),\(\overrightarrow{RS}=(S_x-R_x,S_y-R_y)\)。 二维向量平行充要条件:叉积为 0

\(\text{cross} = v_{1x} \cdot v_{2y} - v_{1y} \cdot v_{2x}\)

  • \(\text{cross} \neq 0\):向量不平行 → \(L_1,L_2\) 不平行,必有交点,直接 Yes。

    ll v1x=Qx-Px,v1y=Qy-Py;
    ll v2x=Sx-Rx,v2y=Sy-Ry;
    ll cross=v1xv2y-v1yv2x;
    if(cross!=0){cout<<"Yes\n";}

情况 2:\(\text{cross}=0\),即 \(PQ \parallel RS\),此时 \(L_1 \parallel L_2\)

平行线分两种:重合 / 分离。 只有两条垂直平分线完全重合时,才存在无穷多公共圆心,输出 Yes;否则无公共圆心,输出 No。

那么,如何判断两条垂直平分线 \(L_1,L_2\) 是否重合?

\(L_1\) 是 PQ 中垂线,\(L_2\) 是 RS 中垂线,且 \(PQ \parallel RS\)。 取 RS 上任意一点(如 R),判断 R 是否在 \(L_1\) 上;再取 S 判断是否在 \(L_1\) 上。 若 \(R,S\) 都在 PQ 的中垂线上 → \(L_1,L_2\) 完全重合。

R 在 PQ 中垂线的充要条件:\(|RP|^2 = |RQ|^2\) 展开距离平方:

\((R_x-P_x)^2+(R_y-P_y)^2 = (R_x-Q_x)^2+(R_y-Q_y)^2\) 移项变形,等价于:

\((2R_x-P_x-Q_x)^2 + (2R_y-P_y-Q_y)^2 = 0\) 同理,S 在 PQ 中垂线等价于:

\((2S_x-P_x-Q_x)^2 + (2S_y-P_y-Q_y)^2 = 0\)

比较平方和是否相等:

复制代码
ll lhs=(2*Rx-Px-Qx)*(2*Rx-Px-Qx)+(2*Ry-Py-Qy)*(2*Ry-Py-Qy);
ll rhs=(2*Sx-Px-Qx)*(2*Sx-Px-Qx)+(2*Sy-Py-Qy)*(2*Sy-Py-Qy);
if(lhs==rhs) cout<<"Yes\n";
else cout<<"No\n";
  • \(lhs=rhs\):\(R、S\) 都在 PQ 中垂线上 → \(L_1=L_2\),无数公共圆心,Yes;
  • \(lhs≠rhs\):\(R、S\) 不在同一条中垂线,两平行线分离,无公共圆心,No。

整体流程概括

对每组测试用例:

  1. 求向量 \(\overrightarrow{PQ},\overrightarrow{RS}\),计算叉积;
  2. 叉积≠0 → 两中垂线相交 → Yes;
  3. 叉积 = 0(线段平行):
    • 计算 R 到 PQ 中点距离平方、S 到 PQ 中点距离平方;
    • 两值相等 → 中垂线重合,存在公共圆心 → Yes;
    • 两值不等 → 中垂线平行分离,无公共圆心 → No。

完整代码

复制代码
#include<bits/stdc++.h>
#define fr1(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define fr2(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define fv(i,p) for(auto (i):(p))
#define ll long long
#define ull unsigned ll
#define pii pair<int,int>
#define pll pair<ll,ll>
#define _1st first
#define _2nd second
#define elif else if
#define debug cout<<endl<<"-------------------------------------------------------------"<<endl
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);
    int T;
    cin>>T;
    while(T--){
        ll Px,Py,Qx,Qy,Rx,Ry,Sx,Sy;
        cin>>Px>>Py>>Qx>>Qy>>Rx>>Ry>>Sx>>Sy;
        ll v1x=Qx-Px,v1y=Qy-Py;
        ll v2x=Sx-Rx,v2y=Sy-Ry;
        ll cross=v1x*v2y-v1y*v2x;
        if(cross!=0){
            cout<<"Yes\n";
        }else{
            ll lhs=(2*Rx-Px-Qx)*(2*Rx-Px-Qx)+(2*Ry-Py-Qy)*(2*Ry-Py-Qy);
            ll rhs=(2*Sx-Px-Qx)*(2*Sx-Px-Qx)+(2*Sy-Py-Qy)*(2*Sy-Py-Qy);
            if(lhs==rhs) cout<<"Yes\n";
            else cout<<"No\n";
        }
    }
    return 0;
}
相关推荐
jinyishu_1 天前
模拟实现 C++ 栈和队列——从适配器模式看懂 STL 容器之美
java·c++·适配器模式
hehelm1 天前
AI大模型接入SDK—通用模块设计
linux·开发语言·c++
hold?fish:palm1 天前
RDB全量快照备份
c++·redis·后端
盐焗鹌鹑蛋1 天前
【C++】C++11:列表初始化、声明、STL升级
c++
ComputerInBook1 天前
c 和 c++ 中的宏块(macro)
c语言·c++··宏块·宏指令
AA陈超1 天前
004 T02 - 俯视角摄像机系统 设计文档
网络·c++·ue5·虚幻引擎
bu_shuo2 天前
c与cpp中的argc和argv
c语言·c++·算法
蓝创精英团队2 天前
VCPKG 跨平台C++ 库管理器
c++·vcpkg
Jayden_Ruan2 天前
C++组合的输出
c++·算法·深度优先