2024“钉耙编程”中国大学生算法设计超级联赛(8)

🚀欢迎来到本文🚀
🍉个人简介:陈童学哦,彩笔ACMer一枚。
🏀所属专栏:杭电多校集训
本文用于记录回顾总结解题思路便于加深理解。

不是哥们,怎么我tm什么都不会。

在这里插入图片描述

1004 cats 的重力拼图

ProblemDescription
cats 有一个有 n 行,每行有 m 个方格的重力拼图。其中第 i 行第 j 个方格坐标为 (i,j)。重力拼图中有一个物块,初始位于坐标 (a,b) 的方格。若当前物块位于 (r,c),在一次操作中,cats 可以选择以下四种操作之一:

  1. 将重力切换为向上:将物块从当前位置移动到 (1,c)。这个过程中物块将经过所有坐标为 (i,c) (1≤i≤r) 的方格。
  2. 将重力切换为向下:将物块从当前位置移动到 (n,c)。这个过程中物块将经过所有坐标为 (i,c) (r≤i≤n) 的方格。
  3. 将重力切换为向左:将物块从当前位置移动到 (r,1)。这个过程中物块将经过所有坐标为 (r,i) (1≤i≤c) 的方格。
  4. 将重力切换为向右:将物块从当前位置移动到 (r,m)。这个过程中物块将经过所有坐标为 (r,i) (c≤i≤m) 的方格。

cats 可以最多进行 142857 次操作。现在 cats 希望最大化被拼图块经过至少一次(包括初始位置和最终位置)的方格的总数。你需要告诉 cats 这个总数的最大值。

解题思路

首先我们发现,一个点只能走到该点的左右极限端点和上下极限端点。
我们先考虑极端条件,当现在的点处于四个角落时,那么显然该点的运动轨迹应该为我们矩阵的最外面的那一圈矩形。
一般条件下的点的话我们则需要额外考虑是n大还是m大。
需要注意的是这里求得是格子数,所以计算答案时应该减去2。
最后还有一个特殊情况就是n 或 m 等于1的时候

AC代码

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 2e5 + 10;
void solve(){
	int n,m,a,b;
	cin >> n >> m >> a >> b;
	int ans = 0;
	//特殊情况 
	if(n == 1 || m == 1){
		cout << n * m << "\n";
		return;
	}
	//极端条件下的格子数 
	ans = (n + m) * 2 - 4;
	//如果在四个角落就直接输出 
	if((a == 1 || a == n) && (b == 1 || b == m)){	
		cout << ans << "\n";
		return;
	}
	int cnt = 0;
	//一般条件下的点的额外贡献 
	if(a > 1 && a < n){
		cnt = max(cnt,m - 2);
	}
	if(b > 1 && b < m){
		cnt = max(cnt,n - 2);
	}
	cout << ans + cnt << "\n";
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t = 1;
	cin >> t;

	while(t --){
		solve();
	}

	return 0;
}

1007 cats 的 k-xor

Problem Description

定义两个数 x,y 的 k-xor 为 x,y 在正整数 k (k≥2) 进制意义下的不进位加法。现在 cats 有两个整数 a,b,cats 算出了它们在某个进制 k 下的 k-xor 为 c。但在 cats 计算出 c 后,cats 忘记了 k 的值。你能帮 cats 算出所有大于等于 2 的可能是 k 的不同正整数个数吗?如果有无穷多个满足条件的 k,输出 −1。

注:两个数在 k 进制下的不进位加法为,将两个数分别写出它们的 k 进制表示,并将两个数对应的位分别相加,然后将每一位相加得到的结果分别对 k 取模,将结果看做一个新的 k 进制数,这个结果即为两个数 k 进制下不进位加法的结果。例如 16=(121)3 和 8=(022)3 在 3 进制下的不进位加法的结果即为 (110)3=12。

解题思路

一般这种有特殊情况的,我考虑先判断出什么情况下会造成特殊情况成立。
那么这里很显然当我们的 a + b = c a + b = c a+b=c时会有无穷个k满足条件,因为只要 k > c k > c k>c即可。
其次当 a + b < c a + b < c a+b<c的时候是没有无解的。因为 a + b a + b a+b是不进位加法,那么无论 k k k为何值
都无法满足 a + b = c a + b = c a+b=c
最后就是 a + b > c a + b > c a+b>c 时,我们观察到a,b,c的最大值为1e9,开个根号大概50000左右。
2 到 50000 我们直接枚举有多少个k满足条件,大于50000的进制必然只有一个,大家可以自己
想想。

AC代码

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 2e5 + 10;
int calc(int a,int b,int k){
	vector<int> f;
	while(a || b){
		int u = a % k;
		a /= k;
		int v = b % k;
		b /= k;
		f.push_back((u + v) % k);
	}
	int sum = 0;
	int res = 1;
	for(auto x : f){
		sum += x * res;
		res *= k;
	}
	return sum;
}
void solve(){
	int a,b,c;
	cin >> a >> b >> c;
	int ans = 0;
	//无穷的情况 
	if(a + b == c){
		cout << -1 << "\n";
		return;
	//0的情况 
	}else if(a + b < c){
		cout << 0 << "\n";
		return;
	//大于50000的情况 
	}else if(a + b - c > 50000) {
		if(calc(a,b,a + b - c) == c){
			ans ++;
		}
	}
	//枚举小范围 
	for(int i = 2;i <= 50000;i ++){
		if(calc(a,b,i) == c){
			ans ++;
		}
	}
	cout << ans << "\n";
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int t = 1;
	cin >> t;

	while(t --){
		solve();
	}

	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陈童学哦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值