视频加载失败

CF 957E Novice's Mistake 题解

1152 字
6 分钟
CF 957E Novice's Mistake 题解

原题#

K1o0n 的第一个编程问题是这样的”Noobish_Monk有 n 个朋友。 (1≤n≤100) 个朋友。每个朋友都给了他 a (1≤a≤10000) 个苹果。 (1≤a≤10000) 个苹果作为生日礼物。收到这样的礼物后,诺比什/蒙克很高兴,他回赠了 b (1≤b≤min(10000,a⋅n)) 个苹果。 (1≤b≤min(10000,a⋅n)) 个苹果给他的朋友们。诺比西和尚还剩下多少个苹果?”

K1o0n 写了一个解决方案,但不小心把 n 的值看成了字符串,所以 n⋅a−b 的值的计算方法不同。具体来说

当用字符串 n 乘以整数 a 时,他将得到字符串 s=n+n+⋯+n+n (a times) 从字符串 s 中减去整数 b 时,将删除最后的 b 个字符。如果 b 大于或等于字符串 s 的长度,则字符串 s将变为空。 了解到这一点后,ErnKor 开始关注在给定的 n 中,有多少对 (a,b) 满足问题的约束条件,而 K1o0n 的解给出了正确答案。

“解法给出了正确答案 “意味着它输出了一个非空字符串,这个字符串转换成整数后等于正确答案,即 n⋅a−b 的值。

输入#

第一行包含一个整数 t ( 1≤t≤100) - 测试用例数。 对于每个测试用例,单行输入包含一个整数 n ( 1≤n≤100)。 保证在所有测试用例中, n 都是不同的。

输出#

对于每个测试用例,按以下格式输出答案: 在第一行,输出整数 x - 给定 n 的坏测试次数。 在接下来的 x 行中,输出两个整数 ai 和 bi - K1o0n 在测试” n “中的解决方案的整数。 ai bi” 得到正确答案。

Input

3
2
3
10

Output

3
20 18
219 216
2218 2214
1
165 162
1
1262 2519

题目大意:#

给你一个整数n,现在对于n*a - b有两种运算:

  1. n作为一个字符往后延伸至a个,然后从最后减去b个字符
  2. n作为一个数字,进行运算n*a - b

需要你求出 (a, b) 不同的组合数,使得两种运算后的结果相同。

思考#

此题的数据范围不大,使用暴力枚举再调整合适的枚举范围是可以通过的。

对于此题,我们容易想到O(n^2)的暴力解法,即从010000枚举a再从 0a*n 去枚举b 但是这样子做必定会超时,我们不可能直接按题目给的范围去直接枚举b

调整上界#

由于在第一种操作中,减去b会使得na减去b个字符,结果的字符串字符数不可能为负数 因此b的上界即是na的字符串的最长长度,即 |n|*a,即 数字n变成字符串后的长度再乘每次枚举的a

所以我们确定b的上界为 |n|*a

int len = 0;
while (tmp[len]) {
arr[len] = tmp[len]-'0';
len++;
}
for (int a = 1; a <= 10000; a++)
for (int b = 0; b <= a*len; b++)

调整下界#

回到题目观察数据范围,我们发现n*a - b的范围是严格小于 10^6的,也就是说,按照第一种操作,字符串的长度最多不会超过6个字符, 于是下界minB的计算:|n|∗a−minB≤6 minB=|n|∗a−6

比较两种计算的值#

十进制逐位加,注意一个小技巧:这里对arr下标取余运算,我们设arr是一个大小为3的数组,下标存的是 n 的每一位数字

val = (n*a) - b; //具体值
rep = (a*len - b); //目标的字符串有多长
if (!val || !rep) {
break;
}
int r = 0;
for (int i = 0; i < rep; i++) {
r = r * 10 + arr[i%len];
}
if (r == val) {
ans.push_back({a, b});
}

题解代码#

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e6+10;
typedef long long ll;
#define x first
#define y second
typedef pair<int, int> P;
void solve() {
int n;
cin >> n;
vector<P> ans;
int val;
int rep;
int d;
int arr[3];
char tmp[256] {};
itoa(n, tmp, 10);
int len = 0;
while (tmp[len]) {
arr[len] = tmp[len]-'0';
len++;
}
for (int a = 1; a <= 10000; a++) {
//对于B: 上界: a*len-1,下界: a*len-6 (在区间内最多不会超过6个字符)
for (int b = max(1, len*a -5); b <= a*len; b++) {
val = (n*a) - b; //具体值
rep = (a*len - b); //目标的字符串有多长
if (!val || !rep) {
break;
}
int r = 0;
for (int i = 0; i < rep; i++) {
r = r * 10 + arr[i%len];
}
if (r == val) {
ans.push_back({a, b});
}
}
}
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); i++) {
cout << ans[i].x << ' ' << ans[i].y << endl;
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int t;
cin >> t;
while (t--)
solve();
return 0;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

CF 957E Novice's Mistake 题解
https://blog.81vm3.xyz/posts/cf957e-novices-mistake/
作者
Blume
发布于
2025-03-09
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Blume
I build interesting things.
公告
欢迎来到我的博客!
分类
标签
最新动态
站点统计
文章
38
分类
5
标签
98
总字数
23,078
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录