题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1226
wa了n发。。之前一直re。找了好久才发现是算c进制化十进制模n时,溢出了。所以得到的余数是负数,然后对数组就访问了非法位置。
代码如下。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=555;
struct key{
int kk[maxn];//因为一个数无法存下密码,所以直接存c进制的数
int len;//密码长度
};
int n,m,c;
int ff[22];
bool mod[5555];//因为密码是5000的倍数并且要最短,所以只需考虑对5000的余数.并且第一次出现该该余数就是最短的答案.
int mm(key s){//返回c进制数转换为十进制数后对n的余数.一直wa在这里
int h=0;
for(int i=0;i<s.len;i++)
h=(h*c+s.kk[i])%n;
return h;
}
/*
原写法
int quick(int x){
int ans=1,k=c;
while(x){
if(x&1)
ans=(ans*k)%n;
k=(k*c)%n;
x>>=1;
}
return ans%n;
}
int mm(key s){
int h=0;
for(int i=0;i<s.len;i++)
h=(h+((s.kk[i]%n)*quick(i))%n)%n;
return h;
}
*/
bool judge(key s){//判断是否全为0
for(int i=s.len-1;i>=0;i--)
if(s.kk[i]!=0) return true;
return false;
}
bool bfs(){
key t,ki;
queue<key> q;
memset(mod,false,sizeof(mod));
for(int i=0;i<m;i++){
t.len=0;
t.kk[t.len++]=ff[i];
q.push(t);
if(ff[i]==0) continue;
int x=mm(t);
if(!mod[x]) mod[x]=true;
}
while(!q.empty()){
t=q.front();
q.pop();
if(mm(t)==0 && judge(t)){
for(int i=0;i<t.len;i++)
if(t.kk[i]>=10) printf("%c",t.kk[i]-10+'A');
else printf("%d",t.kk[i]);
printf("\n");
return true;
}
for(int i=0;i<m;i++){
ki=t;
ki.kk[ki.len++]=ff[i];
int x=mm(ki);
if(ki.len<500&&!mod[x]){//如果长度不超500并且该种余数不出现
q.push(ki);
if(!judge(ki)) continue;
mod[x]=true;
}
}
}
return false;
}
int main(){
int n_case;
scanf("%d",&n_case);
while(n_case--){
scanf("%d%d%d",&n,&c,&m);
for(int i=0;i<m;i++){
char s[2];
scanf("%s",s);
if(s[0]>='0' && s[0]<='9') ff[i]=s[0]-'0';
else ff[i]=s[0]-'A'+10;
}
sort(ff,ff+m);
if(n==0){
if(ff[0]==0) printf("0\n");
else printf("give me the bomb please\n");
}
else if(!bfs())
printf("give me the bomb please\n");
}
return 0;
}