CF1714E Add Modulo 10
这个E题有点怪。
Description
你有一种操作,名曰 x+=x%10,现在给你 \(n\) 个数 \(a_1\) 到 \(a_n\),让你求能否对每个数字进行若干次上述操作使 \(n\) 个数相同。
Analysis
由于操作与个位数有关,故对个位数进行分析。
若个位数为 \(1\),可经一次操作得到 \(2\);
若个位数为 \(3\),可经一次操作得到 \(6\);
若个位数为 \(7\),可经一次操作得到 \(4\);
若个位数为 \(9\),可经一次操作得到 \(2\);
若个位数为非零偶数,则可经若干次操作相互转化(循环),具体表示为:
而对于个位数 \(0\) 和 \(5\),则有转化链:
规律应该都懂了,下面看怎么判断多个数能否转为同一个数。
-
第一种情况:\(\exists a_i,a_i\equiv0\ \text{or}\ 5\pmod{10}\)
则末位为 \(5\) 的数最多进行一次操作,末位为 \(0\) 的进行操作无效。故只需两次特判,一次原序列判断是否全相等,一次判断对末位为 \(5\) 的数操作一次能否是全序列相等,若有一次满足相等,则输出Yes,否则为No。 -
第二种情况:\(\forall a_i,a_i\not\equiv0\ \text{or}\ 5\pmod{10}\)
不妨先对序列不降排序,把除最大数外数的各位都转化为 \(2\) 结尾的数,目的是将各数转化到 \(2486\) 的循环上。
然后对 \(a_n\) 即最大数进行操作,达成一次末位数循环,比如:\(7\to4\to8\to6\to2\)。对于每个操作后的 \(a_n\),都对 \(a_1\) ~ \(a_{n-1}\) 扫描一次判断能否经过操作达到当前的 \(a_n\)。
由于一次 \(2486\) 循环加 \(2+4+8+6=20\),故判断是只需将 \(a_n-a_i\) 的值先模 \(20\),再判断余数是否为 \(0,2=2,2+4=6\) 或 \(2+4+8=14\),若能分解则 \(a_i\) 可经过有限次操作转化为当前的 \(a_n\)。
若有一个操作后的 \(a_n\) 对 \(a_1\) ~ \(a_{n-1}\) 均能达成,则输出 Yes,否则 No。
讲起来有些复杂,举个例子:原序列为 \(44,11\)。
第一步,先排序,得 \(11,44\);
第二步,把除最大值外的数末位操作为 \(2\),得 \(22,44\);
第三步,对 \(44\) 进行末位数循环:\(44\to88\to176\to352\to704\),发现 \(44-22=22\equiv2\pmod{20}\),故 \(a_n\) 原数即可行,故答案为 Yes。
Code
理论明白了,还要用代码实现。
#include <stdio.h>
#include <algorithm>
typedef long long LL;
const LL N = (LL)2e5 + 5, rep[] = {0, 2, 4, 8, 6}, srep[] = {0, 2, 6, 14};
LL n, a[N];
inline bool check(LL x) {
x %= 20;
for (LL i = 0; i < 4; ++i)
if (x == srep[i]) return true;
return false;
}
int main(void) {
LL t; for (scanf("%lld", &t); t--; ) {
scanf("%lld", &n); bool flag = false;
for (LL i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
if (a[i] % 5 == 0) flag = true; //是否存在 x % 5 == 0 的数 x
}
if (flag) {
bool ok = true;
for (LL i = 1; i <= n; ++i) {
if (a[i] % 10 == 5) a[i] += 5;
if (i != 1 && a[i] != a[i - 1]) {ok = false; break;}
}
puts(ok ? "Yes" : "No");
continue;
}
std:: sort(a + 1, a + 1 + n); //排序
for (LL i = 1; i <= n; ++i) //转末位为2
while (a[i] % 10 != 2) a[i] += a[i] % 10;
for (LL i = 0; i < 5; ++i) { //最大数末位循环
a[n] += rep[i]; flag = true;
for (LL j = 1; j < n; ++j)
if (!check(a[n] - a[j])) {flag = false; break;} //判断各数可行与否
if (flag) break;
}
puts(flag ? "Yes" : "No");
}
return 0;
}

浙公网安备 33010602011771号