intmain(){ auto repunit_mod7 = 0; // repunit(k) mod 7 for (int k = 1; ; ++k) { repunit_mod7 = (repunit_mod7 * 10 + 1) % 7; string best = "";
for (int r = 0; r <= 6; ++r) { // For absolute divisibility by 7, all digits must be congruent mod 7. // r=0 => only digit 7 (0 not allowed). r=1,2 have two digits: r and r+7. int d1 = (r == 0) ? 7 : r; int d2 = (r == 1 || r == 2) ? r + 7 : -1;
// Condition for divisibility by 7: either r==0 or repunit(k)≡0 (mod 7). if (r != 0 && repunit_mod7 != 0) continue;
string candidate; if (d2 == -1) { if ((d1 * k) % 9 != 0) continue; candidate.assign(k, char('0' + d1)); } else { // sum = k*d1 + 7*t, where t is count of d2 int mod = (k * d1) % 9; int t0 = (-4 * mod) % 9; // inverse of 7 mod 9 is 4 if (t0 < 0) t0 += 9; int t = -1; for (int x = t0; x <= k; x += 9) { t = x; break; } if (t == -1) continue; candidate.assign(k - t, char('0' + d1)); candidate.append(t, char('0' + d2)); }
if (best.empty() || candidate.size() < best.size() || (candidate.size() == best.size() && candidate < best)) { best = candidate; } }
if (!best.empty()) { cout << best << "\n"; return0; } } }
可绝对整除的正整数 n
假设存在符合条件的,不含 0 的正整数 m,使得 m 的任意排列都是 n 的倍数。显然 n 不能是 10 的倍数,因为 m 的各数位不能为 0。下面我们对 m 分两种情况考虑。
必要性
首先考虑这样的 m,它有至少 2 个相异的数字 x 和 y。我们构造这样两个排列 N1=…xy、N2=…yx,即它们仅在最后两个数位上对调,从而因为有 n∣N1 和 n∣N2,则必须有 n 整除它们的差:
假使这个单词是横向排布的。若单词的中心落在了区域 A 中某行的某个格子中,为了确保单词 EEVEE 的排布,V 的左右两侧两个格子都必须是 E。也就是说,在 A 的某一行中,只要该行存在一个 V,那么该行剩下的格子就必须是 E。
纵向排布的单词同理。
A 内部的对角线(主对角线和副对角线)各有 5 条,长度分别为 1,2,3,2,1,任何一条对角线位于区域 A 内部的距离的最大值为 2。从而,对于一个斜向排布的单词,若单词的中心落在了区域 A,则其对应方向的整条对角线的位于区域内部的格子也不能出现 V。
从而:位于区域 A 内的横向排布的单词的数量,应当小于等于区域 A 内部的恰好只有 1 个 V 的行的数量;位于区域 A 内的纵向排布的单词的数量,应当小于等于区域 A 内部的恰好只有 1 个 V 的列的数量;位于区域 A 内的某个方向上的所有对角线上的单词的数量,应当小于等于区域 A 内该方向上恰好只有 1 个 V 的对角线的数量。
现在,我们假设在区域 A 的 9 个格子中填入了 v 个 V。由上可知:中心落在区域 A 内的 EEVEE 单词的数量,小于等于区域 A 内部的恰好只有 1 个 V 的行的数量、区域 A 内部的恰好只有 1 个 V 的列的数量、和区域 A 内两个对角线方向上恰好只有 1 个 V 的对角线的数量的总和。对 v 进行枚举:首先考虑 v=0 和 v=1 和 v=2 的情况,前两者分别最多激活 0 和 4 条线,后者通过非对角的错位排布可以激活 8 条线。但对于 v≥3 的情况,因为可能会导致单词的重叠,手动统计是痛苦的。我们编写 C++ 脚本,可以统计得到最大的可能性是 11 个单词。但不可能在每一个这样的区域都取到最大值。所以……
int d = r - c; // -2..2 int sumDiag = 0; for (int i = 0; i < 3; ++i) { int j = i - d; if (0 <= j && j < 3) sumDiag += a[i][j]; } int idDiag = 6 + (d + 2); // 6..10 if (sumDiag == 1 && !counted.count(idDiag)) { counted.insert(idDiag); cnt++; }
int s = r + c; // 0..4 int sumAnti = 0; for (int i = 0; i < 3; ++i) { int j = s - i; if (0 <= j && j < 3) sumAnti += a[i][j]; } int idAnti = 11 + s; // 11..15 if (sumAnti == 1 && !counted.count(idAnti)) { counted.insert(idAnti); cnt++; } }
return cnt; };
for (int mask = 0; mask < (1<<9); ++mask) { int val = check(mask); if (val > best) { best = val; bestMask = mask; } }
cout << best << "\n"; // Print one example achieving the maximum for (int r = 0; r < 3; ++r) { for (int c = 0; c < 3; ++c) { int bit = (bestMask >> (r * 3 + c)) & 1; cout << bit << (c == 2 ? '\n' : ' '); } } return0; }