0%

The 6th Liaoning Provincial Collegiate Programming Contest-2025-辽宁省赛-B. Be knocked off 被抠的键盘(构造题,我们需要思考的就是,我们有没有办法化繁为简?)(一般这种构造题目,无解情况不会特别多)

题目大意

题目描述
你有一个包含数字 0099 的键盘。给定一个正整数 mm,你的目标是使用键盘打出一个正整数,使其为 mm 的倍数。

但是,键盘上有 kk正整数按键损坏了(数字 00 的按键一定完好,只有 1199 中的部分按键可能损坏)。你只能使用剩下的完好按键来打出这个数字。

输入格式
第一行包含一个整数 TT1T5×1041 \le T \le 5 \times 10^4),表示测试数据的组数。

对于每组测试数据:
第一行包含两个整数 mmkk1m1071 \le m \le 10^70k90 \le k \le 9),表示目标数字必须是 mm 的倍数,且有 kk 个按键损坏。

用其他剩余按键,敲出 m 的倍数。

第二行包含 kk 个互不相同的整数 pip_i1pi91 \le p_i \le 9),具体表示哪些数字按键被损坏。

输出格式
对于每组测试数据:
如果存在合法的构造方案,请以“连续按下某数字 aabb 次”的操作序列形式输出:
第一行输出一个整数 nn1n1001 \le n \le 100),表示操作的数量。
接下来 nn 行,每行输出两个整数 aabb0a90 \le a \le 91b10181 \le b \le 10^{18}),表示按下数字 aabb 次。

如果不存在任何合法的方案,仅输出一行 -1

样例

1
2
3
4
5
6
7
8
9
10
11
12
输入:
2
37 7
2 3 5 6 7 8 9
7 9
1 2 3 4 5 6 7 8 9

输出:
2
1 3
0 1
-1

样例解释
对于第一组样例,给出的操作为:按下数字 1133 次,然后按下数字 3311 次。这样按出来的正整数是 11101110。由于 1110=37×301110 = 37 \times 30,它是 3737 的倍数,并且只使用了未损坏的按键 1100,符合题目要求。

对于第二组样例,数字 1199 的按键全部损坏,唯一能打出的是由数字 00 组成的数(值为 00)。但题目要求打出的必须是一个正整数,因此无法完成任务,输出 -1

思路讲解

呃,首先我们还是一步一步来吧,就是首先,我们可以想到,就是 m 当中的这个因数还是越少越好嘛,想办法先消掉一些

下面这一步也是比较自然的,因为注意到,0 是永远都在的

我们可以把这个 m 当中的因数 2,5 给除掉(因为如果原数字不满足,就加 0 即可),得到的新 m 和这个 10 互质(反正应该就是想办法让原数和 10 互质,可以通过不断除以 10,记录一下除 10 的这个个数,最后 +0 即可)。

然后,就可以想到欧拉定理(其实我们的构造目标就是一个同余式,我们得到的任何东西,也要想办法化为同余式):

这是 Euler 定理(欧拉定理)。

对于任意正整数 mm 和整数 aa,若 gcd(a,m)=1\gcd(a, m) = 1,则

aφ(m)1(modm)a^{\varphi(m)} \equiv 1 \pmod{m}

image

不难得出如下结论:

image

我们现在是构出来了,但是万一 9 被扣了我们不就炸了?

我们发现,只要我们能够勾出来一个全 1 的,我们能够非常自然的勾出全 d 的。

image

这个最后一步,也挺难的,反正我确实不大能够推出来。使用了变量直接代换的这个技巧,把一个 9 带到了这个整除符号的两边。

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ll cnt2=0;
while (M%2==0) {
M/=2;
cnt2++;
}
ll cnt5=0;
while (M%5==0) {
M/=5;
cnt5++;
}
ll phi=euler_phi(M);
ll cnt0=max(cnt2,cnt5);
if (cnt0==0) {
cout<<1<<"\n";
}else {
cout<<2<<"\n";
}
cout<<*keys.rbegin()<<" "<<9*phi<<"\n";
if (cnt0!=0) {
cout<<0<<" "<<cnt0<<"\n";
}

AC代码

AC
https://codeforces.com/gym/106380/submission/366492238

心路历程(WA,TLE,MLE……)3737111b10181 \le b \le 10^{18}