Multiple
Time Limit: 1000MS | Memory Limit: 32768K | |
Total Submissions: 7215 | Accepted: 1546 |
Description
a program that, given a natural number N between 0 and 4999 (inclusively), and M distinct decimal digits X1,X2..XM (at least one), finds the smallest strictly positive multiple of N that has no other digits besides X1,X2..XM (if such a multiple exists).
Input
The input has several data sets separated by an empty line, each data set having the following format:
On the first line - the number N
On the second line - the number M
On the following M lines - the digits X1,X2..XM.
On the first line - the number N
On the second line - the number M
On the following M lines - the digits X1,X2..XM.
Output
For each data set, the program should write to standard output on a single line the multiple, if such a multiple exists, and 0 otherwise.
An example of input and output:
An example of input and output:
Sample Input
22 3 7 0 1 2 1 1
Sample Output
110 0
Source
题目大意:
输入一个数字N,给出一些0~9的数字,求每一位都有这些数字组成的最小的N的倍数的正整数,如果不存在输出0。
解题思路:
BFS搜索,我们先把这些给出的数字排序,这样就可以保证先搜索的是最小的。然而如果直接这样搜索,绝对会TLE,因此我们需要使用同余定理进行剪枝。
由同余定理可知:对于A,B两个数,如果A%N==C&&B%N==C,即A==a*N+C&&B=b*N+C,如果我们在后面再加一个数X,则A*10+X==a*N*10+C*10+X、B*10+X==b*N*10+C*10+X,所以对于任意膜N相当两个数,再它们之后再加一个数字形成的新数字膜N一定相等。又应为题目要我们输出最小的值,对于后面出现的膜相等的数一定比第一个大,所以就没有必要对它们进行搜索。利用这一点就可以非常有效的进行剪枝。
还有一点,由于这个数字可以非常大,会远远超过long long,我们要在bfs队列中每一次保存当前位数,最后用类似链表的方法输出(用大数不知道会不会超时,我没有试)。
最后还需要特别注意一下当N等于0的时候需要特判,否则会RE。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
struct Point
{
int last,left,now;//上一个数字的下标,余数,当前数字
Point(int la=0,int le=0,int n=0):last(la),left(le),now(n){}
};
const int maxn=4999+5;
const int maxm=10+5;
int N,M,digit[maxm];
Point que[maxn*400];//用数组模拟队列
bool vis[maxn];
int bfs()
{
memset(vis,0,sizeof vis);
int s=0,t=0;
for(int i=0;i<M;++i)
{
if(digit[i]==0)
continue;
que[t++]=Point(-1,digit[i]%N,digit[i]);
if(digit[i]%N==0)
return i;
vis[digit[i]%N]=true;
}
while(t>=s)//队列为空,说明不存在这样的数。
{
for(int i=0;i<M;++i)//枚举下一位
{
Point p=que[s];
p.last=s;
p.left=(p.left*10+digit[i])%N;
p.now=digit[i];
if(vis[p.left])//余数已经出现过,没必要继续搜索
continue;
vis[p.left]=true;
que[t++]=p;
if(!p.left)
return t-1;
}
++s;
}
putchar('0');
return -1;
}
void out(int x)//输出
{
if(x==-1)
return ;
out(que[x].last);
putchar('0'+que[x].now);
}
int main()
{
while(~scanf("%d%d",&N,&M))
{
for(int i=0;i<M;++i)
scanf("%d",&digit[i]);
sort(digit,digit+M);
if(N==0)//N==0特判
puts("0");
else
{
out(bfs());
putchar('\n');
}
}
return 0;
}