专栏文章

CF2109C1 Hacking Numbers (Easy Version) 解题报告

CF2109C1题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mip8yy8x
此快照首次捕获于
2025/12/03 08:06
3 个月前
此快照最后确认于
2025/12/03 08:06
3 个月前
查看原文

题目大意

交互题。TT 组数据,每组给定一个整数 n(1n109)n(1\le n\le 10^9),评测机中有一个隐藏的整数 x(1x109)x(1\le x\le10^9)。你可以对这个隐藏的 xx 做出以下四种操作若干次(这里 C1 这道题要求最多 77)将隐藏的 xx 变成 nn
  1. add y 表示将 xx 增加 y(1018y1018)y(-10^{18}\le y\le 10^{18})
  2. mul y 表示将 xx 乘上 y(1y1018)y(1\le y\le 10^{18})
  3. div y 表示将 xx 除以 y(1y1018)y(1\le y\le 10^{18})
  4. digit 表示将 xx 的十进制各位数字相加,赋值给 xx
在以上的四种操作中,如果假设 xx 操作后得到的数为 resres,那么当且仅当 1res10181\le res\le 10^{18}resres 为整数时此次操作有效,交互机会返回 11,否则这次操作无效,xx 不做改变,交互机返回 00
在确定 x=nx=n 时给交互机一个指令 ! 结束这组数据,这时交互机会返回一个值 11(正确)或者 1-1(错误)。

解题思路

一种思路为可以将 xx 经过若干次操作后使得 xx 变成我们可以确定的数,然后再经过最多一次操作使得 xx 变为 nn。这里我们需要保留最后一次将 xx 由我们已知的数字变为 nn 的过程,那么题意就变成了:最多 66 次操作使得 xx 变成一个确定的数
那么如何去选取这个确定的数呢?最容易想到的这个确定的数就是 11。将 x(x1)x(x\ge 1) 变为 11,显然就是要将 xx 这个数缩小。如何进行缩小?这就锁定了 digitadddiv 三种操作。由于 div 操作必须是整除这次操作才有效,所以我们这里不考虑 div 操作。
  1. 第一次缩小:显而易见 digit 操作可以将这个范围缩小到更小,于是:1x1091x81(x=1091 时取到 81)1\le x\le 10^9\to1\le x\le81(x=10^9-1\ 时取到\ 81)
  2. 第二次缩小:这里再用一次 digit 操作可以将范围继续缩小,于是:1x811x16(x=79 时取到 16)1\le x\le 81\to1\le x\le16(x=79\ 时取到\ 16)
  3. 第三次缩小:注意这里如果再用一次 digit 操作最多最多将 xx 缩小到 1x91\le x\le 9,而运用 add 操作每次可以将范围折半,即 add y 这里 yyx2\left \lceil \frac{x}{2} \right \rceil ,这样我们就可以用 add -8 操作得到:1x161x81\le x\le 16\to1\le x\le8
  4. 同理可得第四次缩小 add -4 得到 1x81x41\le x\le 8\to1\le x\le4
  5. 第五次缩小 add -2得到1x41x21\le x\le 4\to1\le x\le2
  6. 第六次缩小 add -1得到1x2x=11\le x\le 2\to x=1
六次结束,这里 xx 已经是 11,可以最多一次操作得到 nn,这里有个细节:你可以进行 mul nadd n-1 两种操作得到 nn,但是如果用了后者,你会得到 TLE 的好成绩,原因是当 n=1n=1 时,你给出了不合法的操作 add 0,所以避免特判,我选择了前者。
单次时间复杂度 O(1)O(1)
不要忘记每次输出后清空缓存区哦

AC Code

这里只放主函数。
CPP
signed main()
{
	int T=re();
	while(T--)
	{
		int n=re();
		int ci=2;
		while(ci--)
		{
			puts("digit");
			cout.flush();
			int op=re();
		}
		puts("add -8");
		cout.flush();
		int op=re();
		puts("add -4");
		cout.flush();
		op=re();
		puts("add -2");
		cout.flush();
		op=re();
		puts("add -1");
		cout.flush();
		op=re();
		printf("mul %d\n",n);
		cout.flush();
		op=re();
		puts("!");
		cout.flush();
		op=re();
	}
	return 0;
}


评论

0 条评论,欢迎与作者交流。

正在加载评论...