Yet Another Multiple Problem
Time Limit: 40000/20000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 5086 Accepted Submission(s): 1141
In this problem, you’re asked to solve the following question: Given a positive integer n and m decimal digits, what is the minimal positive multiple of n whose decimal notation does not contain any of the given digits?
For each test case, there are two lines. The first line contains two integers n and m (1 ≤ n ≤ 10 4). The second line contains m decimal digits separated by spaces.
Input is terminated by EOF.
2345 3 7 8 9 100 1 0
Case 1: 2345 Case 2: -1
此题题意就是说给你一个数n,然后再给你m个数字,问你最小的不含着m个数字的n的倍数,这题很容易想到的就是从高位到低位,从小数到大树的方法进行一一枚举,这样枚举出来先得到的一定是最小的,但是那么问题来了,怎么进行判定没有结果呢,显然,如果不对没有结果这种结果进行处理的话一定会陷入一个死循环内,我们一定要对其进行判定,这时此题就摇身一变,从一个暴力题变成了一个数论题(好吧,其实这题本来就是一个数论题),接下来小编就要给出这个数论题的推导过程了(数论题最重要的不是思路,而是推导过程对吧~)。
设k,i是两个常数,A=k*B+C(即A%B=C),则:
1.(A+i)%B = C+i%B
2.(A*i)%B = (C*i)%B
证明到这里你可能会问小编……跟这题有什么关系,额…这个嘛,确实没什么关系(害怕……),但是上面两个式子直观的给我们展示了一个道理,那就是对一个数进行处理后对某个数的取模值,相当于是对其处理前的取模值进行处理。接下来小编给出关键的证明过程。
设k1,k2,i是两个常数,A1=k1*B+C(即A1%B=C),A2=k2*B+C(即A2%B=C),则:
1.(A1+i)%B = (A2+i)%B = C+i%B
2.(A1*i)%B = (A2*i)%B = (C*i)%B
如果两个数对某个数的取模相等,那么对他们进行相同的处理,得到的结果是一样的(绕了这么大的圈终于到重点了),也就是说如果我们子啊进行处理的时候遇到两个数对某个数的取模相等的话,就可以跳过这个条件,会到题目,这下你可能会知道什么时候会没有结果了吧,那就是当我们队某个数的取模的所有值全部情况都遍历到了(比如对n取模,0~n-1的情况都出现过了),而没得到结果的话,那就说明这种情况是没有结果了。遍历的过程我们就运用BFS来实现吧
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1e4+5;
bool vis[N],del[10];
int n,pre[N];
char ans[N];
bool bfs()
{
queue<int> Q;
Q.push(0);
while(!Q.empty())
{
int cur = Q.front();
Q.pop();
for(int i=0; i<10; i++)
{
if(del[i] || cur==0&&i==0)
continue;
int next = (cur*10+i) % n;
if(vis[next]) continue;
ans[next] = '0'+i;
vis[next] = true;
pre[next] = cur;
Q.push(next);
if(next == 0) return true;
}
}
return false;
}
void solve()
{
string res;
int p = 0;
while(p!=0 || res.empty())
{
res += ans[p];
p = pre[p];
}
reverse(res.begin(),res.end());
puts(res.c_str());
}
int main()
{
int m,T=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(vis,0,sizeof(vis));
memset(del,0,sizeof(del));
while(m--)
{
int k;
scanf("%d",&k);
del[k] = true;
}
printf("Case %d: ",++T);
if(bfs()) solve();
else printf("-1\n");
}
return 0;
}