[爆搜]Torchbearer
题目大意
给定一个正整数 \(n\) , 求最小的正整数 \(m\) 满足 \(n * m\) 的值的每位由 \(0, 1\)构成(十进制下)。
思路
本来看到 \(0,1\)串,想到的是用二进制搞。
但是发现自己这方面存在大锅,而且人也很菜。
于是转变了思考方向。
对于乘积的每一位都是由 \(0,1\) 构成,那么考虑模拟乘法。
因为乘法每次都是高一位的,所以每次考虑枚举 \(0\) 到 \(9\) 作为所求的 \(m\) 这一位。
每次就取出最后一位,让最后一位和上一次除最后一位的剩余贡献的最后一位相加,所得的数经过整除十后应该是 \(0\) 或 \(1\)。
再想,当除最后一位剩余的数加上上一次除最后一位的剩余贡献的和也是一个 \(0,1\) 串时,那么这个 \(m\) 就是显然成立的。
再考虑如何优化。
显然,这个算法是从后往前模拟的,所以无法在模拟中直接判断大小。
考虑在每一位搜完这一层再搜下一层,这样当这一层有结果时,下面几层的解显然是劣与这一层的结果的(位数)。
还有考虑 \(m\) 不为 \(0\) 的情况。
数据(这个数据真的水,999,9999,99999的情况都没有,这些的结果都是暴ull的。特别是99999,长度高达42位。。。)删除
Code
#include <bits/stdc++.h>
#define ll unsigned long long
#define INF 1844674407370955161
using namespace std;
ll a[10];
ll n, len, ans = INF, fir = 1;
void hhd (ll last, ll d, ll base)
{
if (d > ans) return ;
if (!d)
{
if (fir) fir = 0;
else return ;
}
ll aut[15];
for (int i = 0; i <= 9; ++ i)
{
// printf ("last = %d d = %d i = %d result = %d\n", last, d, i, a[len] * i % 10 + last % 10);
aut[i] = 0;
ll kt = a[len] * i % 10 + last % 10;
if (kt % 10 == 1 || kt % 10 == 0)
{
ll te = (n * i + last) / 10, tes, fl = 1, rt;
tes = te;
while (tes)
{
rt = tes % 10;
if (rt != 1 && rt != 0)
{
fl = 0;
break;
}
tes /= 10;
}
//printf ("d = %d te = %d i = %d last = %d kt = %d fl = %d\n", d, te, i, last, kt, fl);
if (fl && d)
{
ans = min (ans, d + i * base);
return ;
}
else aut[i] = 1;
}
}
for (int i = 0; i <= 9; ++ i)
{
// printf ("last = %d d = %d i = %d result = %d\n", last, d, i, a[len] * i % 10 + last % 10);
if (aut[i])
{
ll te = (n * i + last) / 10;
hhd (te, d + i * base, base * 10);
}
}
}
int main ()
{
scanf ("%d", &n);
ll n_ts = n;
while (n_ts)
{
a[++ len] = n_ts % 10;
n_ts /= 10;
}
ll a_ts[10];
for (int i = 1; i <= len; ++ i) a_ts[i] = a[i];
for (int i = 1; i <= len; ++ i) a[i] = a_ts[len - i + 1];
hhd (0, 0, 1);
if (ans != INF) printf ("%lld", ans);
else printf ("no solution");
return 0;
}