noip模拟题 考场爆搜文件名打错了ovo 最后稳打铁
如果答案在
int64
i
n
t
64
范围之内, 那么你爆搜枚举每一位就可以跑过去
如果答案
>1e18
>
1
e
18
又因为是限制一些数不能选, 我们可以考虑数位dp
设
f[i]
f
[
i
]
表示模k后等于i的最小的数 那么每次可以枚举可用数进行转移
由题意可以知道一个数显然是由他的前驱*10 + (0, 9) 组成的
所以只需要记下最小的一个数即可
如果答案很多位的话数组存不下来
我们记下最后一位和他的前驱就ojbk啦
题目戳我
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define chkmin(a, b) (a > b ? a = b, 1 : 0)
using namespace std;
typedef unsigned long long ull;
const int maxn = 1e6 + 10;
int pre[maxn], a[10], t, k, vis[10], cnt;
int f[maxn];
void out(int x)
{
if(pre[x])
out(pre[x]);
printf("%d", f[x]);
}
void solve()
{
queue<int> q;
For(i, 1, cnt)
if(a[i] != 0)
{
f[a[i] % k] = a[i], q.push(a[i] % k);
if(f[0] != -1)
return void(printf("%d\n", a[i]));
}
while(!q.empty())
{
int x = q.front();
q.pop();
if(x == 0 && f[x] != -1)
return out(0);
For(i, 1, cnt)
if(f[(x * 10 + a[i]) % k] == -1)
{
f[(x * 10 + a[i]) % k] = a[i];
pre[(x * 10 + a[i]) % k] = x;
q.push((x * 10 + a[i]) % k);
}
}
puts("-1");
}
int main()
{
freopen("digit.in", "r", stdin);
freopen("digit.out", "w", stdout);
int x;
scanf("%d%d", &k, &t);
if(t == 0)
return printf("%d\n", k), 0;
if(t == 10)
return printf("-1\n"), 0;
memset(f, -1, sizeof(f));
For(i, 1, t)
{
scanf("%d", &x);
vis[x] = 1;
}
For(i, 0, 9)
if(!vis[i])
a[++ cnt] = i;
solve();
return 0;
}