New Maths
题面:
中文题意:
定义运算a⊗b为a乘b无进位的结果,现在给一个数n,找到最小的a,使得a⊗a等于n。
思路:
题目是求a⊗a,需要枚举a的每一位。
通过上面的c[k],我们知道枚举到当前位的数字,这一位对应的乘积结果也可以通过公式计算出来。
每一位从0->9枚举一遍,将得到的c[k]和输入的n的第k位比较,相同的话就进入下一个数位的枚举。
最后将第一次得到的输出即可,这能保证是最小的a。
具体细节:
- 枚举的时候,可以知道a的位数肯定是len(n)/2向上取整的,所以就定义
len1 = (len(n)+1)/2
- 在
1<=当前枚举位<=len1
的时候枚举这个位置上放0->9的情况。 - 在
len1<当前枚举位<=len(a)
的时候校检得到的乘积对应位和n的对应位是否相等。 - 最后递归出口
当前位>len
的时候输出得到的数组即可。
时间复杂度O(2m),其中m<=13,时间复杂度可以接受
代码:
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int len1;
int len;
int num[500];
int a[500];
bool flag;
void dfs(int pos) {
if (flag)return;
//已经找完a了就全部退出
if (pos > len)
//找到了
{
flag = 1;
//标记
for (int i = 1; i <= len1; i++) cout << a[i];
cout << endl;
//输出a数组
return;
}
for (int i = 0; i <= 9; i++)
//枚举该位上10个数
{
int tmp = 0;
//计算c[k]
a[pos] = i;
//赋值给a
if (pos > len1 && i > 0) return;
//超过len1只需要校检
//pos>len1时计算只能加上前导零,如12->012->0012,若i>0,直接不符合
for (int j = 1; j <= pos; j++) {
tmp += ((a[j] * a[pos - j + 1]) % 10);
//c[k] = a[1]⊗b[k] + a[2]⊗b[k-1] + ... + a[k]⊗[b1]
tmp %= 10;
//去除进位
}
if (tmp == num[pos])dfs(pos + 1);
//若这个位满足题意,进入下一位枚举
}
}
int main() {
flag = 0;
string s;
cin >> s;
len = s.size();
//得到n长度
len1 = (len + 1) >> 1;
//输出字符串的长度,因为没有进位,所以一定是(L + 1 >> 1)
for (int i = 1; i <= len; ++i)
//先将字符串变成int数组
num[i] = s[i - 1] - '0';
dfs(1);
//取到第几位
if (!flag)cout << -1 << endl;
//如果dfs中没有输出,就输出-1
return 0;
}