题目:
https://www.luogu.com.cn/problem/P1092
**爸爸的话:**孩子第一次做 提高/省选 的题目,在3个多小时的坚持下,还是80分,不过孩子没有崩溃,还打算用算法宝典里面另外一个思路从零开始,努力和心态都很值得点赞。
最后在老师的点拨下,找到AC的办法,从80到100分,是需要靠幸运,也是一个经验和经历。记录这一刻。
孩子的AC代码,注意第十九行,之前是 for (int i = 0; i < n; ++i)
只有80分,过不了。这就是幸运的加分。#_#!
#include <iostream>
#include <cstdio>
#include <algorithm>
#define SIZE 26 + 10
using namespace std;
int n, number[SIZE + 65], next[SIZE], top;
char a[SIZE], b[SIZE], c[SIZE];
bool vis[SIZE + 65];
void dfs(const int &);
bool pd();
bool can();
void get(const char &);
int main() {
freopen("cpp.in", "r", stdin);
freopen("cpp.out", "w", stdout);
scanf("%d%s%s%s", &n, &a, &b, &c);
for (int i = n-1; i >= 0; --i) {
get(a[i]);
get(b[i]);
get(c[i]);
number[i + 65] = -1;
}
for (int i = 0; i < n; ++i) {
vis[i] = false;
}
dfs(0);
return 0;
}
void dfs(const int &t) {
if (can()) {
return;
}
if (t == n) {
if (pd()) {
for (int i = 0; i < n; ++i) {
printf("%d ", number[i + 65]);
}
exit (0);
}
return;
}
for (int i = n - 1; i >= 0; --i) {
if (!vis[i]) {
vis[i] = true;
number[next[t]] = i;
dfs(t + 1);
number[next[t]] = -1;
vis[i] = false;
}
}
}
bool pd() {
int x = 0;
for (int i = n - 1; i >= 0; --i) {
int A = number[a[i]], B = number[b[i]], C = number[c[i]];
if ((A + B + x) % n != C) {
return false;
}
x = (A + B + x) / n;
}
return true;
}
bool can() {
if (number[a[0]] + number[b[0]] >= n) {
return true;
}
for (int i = n - 1; i >= 0; --i) {
int A = number[a[i]], B = number[b[i]], C = number[c[i]];
if (A == -1 || B == -1 || C == -1) {
continue;
}
if ((A + B) % n != C && (A + B + 1) % n != C) {
return true;
}
}
return false;
}
void get(const char &ch) {
if (!vis[ch]) {
vis[ch] = true;
next[top++] = ch;
}
}
题解: https://www.luogu.com.cn/problemnew/solution/P1092
这个题官方正解是高斯消元,可是我不会啊QAQ。
说一下搜索怎么做
这个题目第一个难点在于你要理解 nn 进制的加法
nn 进制的加法就是在十进制的基础上满十进一改成满nn 进一
由于这道题只考虑加法,所以进位只可能是 11 ,证明小学生都会,略
搜索的大体思路就是从第 11 位的值开始搜,搜到最后一位,判断是否合法
考虑剪枝
33 个字符串的长度都是 nn ,由此可以想到一个最简单的剪枝
最高位不能有进位
如果有进位,显然第 33 个串的长度不会是 nn ,而是n+1n+1,这并不合法
一个剪枝显然不够啊,再想一个
文字不太好描述,我们看图(不会用latex写竖式啊QAQ)
qwq
假设这是十进制下的加法,怎么判断这个竖式对不对?
显然这个竖式是错误的,因为个位上(8+6) mod 10=4 \not=5(8+6)mod10=4̸=5
由此推广到每一位,但是还要考虑进位,不慌,看另一张图
qwq
这个竖式是对的还是错的?
这并不好判断,虽然(8+6) mod 10=4 \not=5(8+6)mod10=4̸=5,但是这是中间位,有可能有进位
如果有进位, 那么(8+6+1) mod 10=5(8+6+1)mod10=5,这一位就是合法的了。
综合上面的分析,得到了另一个剪枝方法
用 AA 和 BB 表示两个加数,用 CC 表示两个加数的和
如果某 ii 位,满足(A[i]+B[i])mod;n\not=Cimodn̸=C[i] 和 (A[i]+B[i]+1)mod;n\not=Cimodn̸=C[i]
根据上面的分析,这种状态肯定不对,直接 returnreturn 就好了
或许还有别的剪枝,但是这两个应该够用了
我的代码里还用了一个玄学的 nextnext 数组,有什么用照着样例手推一遍就知道了,比较好理解。实在看不懂可以私信我qwq
学习科学,实用玄学——某钟姓dalao