题目描述:所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。
你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。
样例输入:
5
ABCED
BDACE
EBBAA
样例输出:
1 0 3 4 2
【数据规模】
对于30%的数据,保证有N≤10;
对于50%的数据,保证有N≤15;
对于全部的数据,保证有N≤26。
下面题解开始:
如果我们直接暴搜显然是不行的复杂度有 O(nn) 。。。。
那么我们可以发现因为有 n 列那么,那么我们可以发现令第一行第 i 个为 xi ,第二行第 i 个为 yi , 第三行为 zi
当前的数字在不在给定的范围内
因为大部分的情况下枚举完成带入时如果不合法那么第一个 A 很容易就无法被整除了所以实际的复杂度更加接近于 O(2n−1n)
开始写吧!!!
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN = 26;
int _abs(int u){return u>0?u:-u;}
int gcd(int a, int b){
int c;
while(b){
c = a % b;
a = b;
b = c;
}
return a;
}
int Ma[MAXN+10][MAXN+10], g[MAXN+10][MAXN+10], d[MAXN+10], n, x[MAXN+10];
bool vis[MAXN+10];
bool check(){
memset(vis, 0, sizeof vis);
for(int i=1;i<=n;i++){
int sum = 0;
for(int j=2;j<=n;j++)
sum += d[j] * g[i][j];
if(sum % Ma[i][i] != 0) return false;
sum /= Ma[i][i];
if(sum < 0 || sum >= n) return false;
if(vis[sum]) return false;
vis[x[i] = sum] = true;
}
return true;
}
void dfs(int u){
if(u == 1){
if(check()){
for(int i=1;iprintf("%d ", x[i]);
printf("%d\n", x[n]);
exit(0);
}
return ;
}
d[u] = 0; dfs(u-1);
d[u] = 1; dfs(u-1);
}
void solve(int n){
int col, row;
for(col=row=1;row<=n&&col<=n;row++,col++){
int Maxp = row;
for(int i=row+1;i<=n;i++)
if(_abs(Ma[i][col]) > _abs(Ma[Maxp][col]))
Maxp = i;
if(Maxp != row){
swap(Ma[Maxp], Ma[row]);
swap(g[Maxp], g[row]);
}
for(int i=1;i<=n;i++){
if(i != row && Ma[i][col] != 0){
int lcm = Ma[i][col] * Ma[row][col] / gcd(Ma[i][col], Ma[row][col]);
int d1 = lcm / Ma[i][col], d2 = lcm / Ma[row][col];
for(int j=1;j<=n;j++){
Ma[i][j] = Ma[i][j] * d1 - Ma[row][j] * d2;
g[i][j] = g[i][j] * d1 - g[row][j] * d2;
}
}
}
}
}
char s1[MAXN+10], s2[MAXN+10], s3[MAXN+10];
int main(){
scanf("%d", &n);
scanf("%s%s%s", s1+1, s2+1, s3+1);
memset(Ma, 0, sizeof Ma);
for(int i=1;i<=n;i++){
++Ma[i][s1[i]-'A'+1];
++Ma[i][s2[i]-'A'+1];
--Ma[i][s3[i]-'A'+1];
g[i][i] = n, g[i][i+1] = -1;
}
solve(n);
dfs(n);
return 0;
}
另有搜索算法请见搜索大法好