【ZOJ】4061-Magic Multiplication 思维+模拟
题意
定义\(A \otimes B = \sum\limits_{i=1}^n\sum\limits_{j=1}^m a_ib_j = a_1b_1 + a_1b_2 + \dots + a_1b_m + a_2b_1 + \dots + a_nb_m\)
现在给出 \(A\) ,\(B\) 的位数以及 \(A \otimes B\),输出 \(A\) 的值以及 \(B\) 的值,如果有多个答案,优先输出 \(A\) 的最小值。
思路
比赛的时候自己被自己迷惑住了。
队友说枚举 \(A_1\) ,就可以求出唯一一个 \(A_1\) 对应的 \(B\),我一直不信,因为主观认为对于 \(A_1\) 无法从给出的 \(A \otimes B\) 看出对应的 \(A_1 \times B_i\) 是一位还是两位,所以可能对于一个 \(A_1\) 可能求出很多个 \(B\)。
但是后来仔细一想,对于一个 \(A_1\) 只可能有一个 \(B\)。
当时时间不是很多了,中间浪费了一段时间,没有写完。
赛后补了。
首先枚举 \(A_1\) 的值 [1,9],然后我们遍历 \(A \otimes B\) ,先用 1 位除 \(A_1\),如果一位不行,就用两位,如果两位都不行,那么这个\(A_1\)就不合适。
直到得到 \(m\) 个数字,即 \(B\)。
这时再用剩下的 \(A \otimes B\) "除" \(B\),和上面步骤类似,验证得到的 \(A\) 是否合法,如果合法,存起来这对 \(A,B\),排个序,输出最小的。
代码
/*
* @Autor: valk
* @Date: 2020-08-21 11:06:28
* @LastEditTime: 2020-10-12 10:15:27
* @Description: 如果邪恶 是华丽残酷的乐章 它的终场 我会亲手写上 晨曦的光 风干最后一行忧伤 黑色的墨 染上安详
*/
#include <bits/stdc++.h>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;
int n, m;
char str[N];
vector<int> a, b;
struct node {
char a[N], b[N];
} ans[100];
int tot;
bool cmp(node x, node y)
{
if (strlen(x.a) == strlen(y.a))
return strcmp(x.a, y.a) < 0;
return strlen(x.a) < strlen(y.a);
}
void getb(int pos)
{
if(b[0]==0)
return;
int len = strlen(str + 1);
for (int i = 1; i < n; i++) {
vector<int> temp;
for (int j = 0; j < m; j++) {
if (pos > len) {
return;
}
int now = str[pos] - '0';
if (b[j] == 0) {
if (now)
return;
++pos;
} else {
if (now % b[j] == 0 && now / b[j] < 10) {
temp.pb(now / b[j]);
++pos;
} else {
if (pos == len)
return;
now = now * 10 + str[pos + 1] - '0';
if (now % b[j] == 0 && now / b[j] < 10) {
temp.pb(now / b[j]);
pos += 2;
} else
return;
}
}
}
sort(temp.begin(), temp.end());
temp.erase(unique(temp.begin(), temp.end()), temp.end());
if (temp.size() == 0)
temp.pb(0);
if (temp.size() == 1) {
a.pb(temp[0]);
} else {
return;
}
}
if (pos != len + 1||a.size()!=n)
return;
tot++;
for(int i=0;i<n;i++){
ans[tot].a[i] = a[i] + '0';
}
ans[tot].a[n] = '\0';
for (int i = 0; i < m;i++){
ans[tot].b[i] = b[i] + '0';
}
ans[tot].b[m] = '\0';
}
void enumer()
{
for (int i = 1; i < 10; i++) {
a.clear(), b.clear();
a.pb(i);
int pos = 1;
for (int j = 1; j <= m; j++) {
int now = str[pos] - '0';
if (now % i == 0 && now / i < 10) {
b.pb(now / i);
pos += 1;
} else {
now = now * 10 + str[pos + 1] - '0';
if (now % i == 0 && now / i < 10) {
b.pb(now / i);
pos += 2;
} else {
break;
}
}
}
if (b.size() == m) {
getb(pos);
}
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--) {
tot = 0;
scanf("%d%d%s", &n, &m, str + 1);
enumer();
if(tot==0){
printf("Impossible\n");
}else{
sort(ans + 1, ans + 1 + tot, cmp);
printf("%s %s\n", ans[1].a, ans[1].b);
}
}
return 0;
}