hdu 超级密码 1226

/*
同余的定义:如果m|(a-b)则a同余b即a与b对m取余后的余数相同
定理:
【1】如果a1同余b1(mod m) a2同余b2(mod m)则a1*a2同余b1*b2(mod m)
【2】如果a1同余b1(mod m)  a2同余b2(mod m)则a1+a2同余b1+b2(mod m)
证明:
1)a1=b1+k1*m  a2=b2+k2*m
a1*a2=b1*b2+(k1*b2+k2*b1+k1*k2*m)m
所以a1*a2同余b1*b2(mod m)
2)
a1=b1+k1*m  a2=b2+k2*m
a1+a2=b1+b2+(k1+k2)m
所以a1+a2同余b1+b2(mod m)


如果a和b同余则成上同一个数后一定还是同余的
证明:假设数乘上一个数x 
a同余b(mod m) x同余x(mod m)
运用上述定理得ax同余bx(mod m)
举个例子:
N=11 C=10
10
0 1 2 3 4 5 6 7 8 9 10
123同余2(mod m)当在后面加上一个数后相当于先乘上10 两个数还同余 在加上同一个数后还同余 即余数相同那么就没必要
搜123了
所以我们标记一下余数就可以了,因为余数最多有5000个 
*/
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int num[20],N,C,flag[5005];//flag数组标记r数是否出现过如果余数已经出现过就没必要在进行搜索了,num的0,1判断是否有这个数,也减少了排序
struct node
{
    int nu[505];
    int len;//数的长度
};
void Print(node q)//数的输出
{
    int i;
    for(i=0; i<q.len; i++)
    {
        if(q.nu[i]<10)
            printf("%d",q.nu[i]);
        else
            printf("%c",q.nu[i]+'A'-10);
    }
    puts("");
}
int Mod(node q)//大数取模
{
    int i,temp=0;
    for(i=0; i<q.len; i++)
    {
        temp=(temp*C+q.nu[i])%N;
    }
    return temp;
}
int bfs()
{
    int i;
    queue<node> v;
    while(!v.empty())
        v.pop();
    node l;
    for(i=1; i<16; i++)//这一层for循环是把每个元素都放到队列里头,队列中的点的长度都为1
    {
        if(!num[i])//当num[i]为0时说明i这个数不存在
            continue;
        l.len=1;//把每个数的长度都初始化为1
        l.nu[0]=i;
        int r=Mod(l);
        if(r==0)
        {
            Print(l);
            return 1;
        }
        else
        {
            flag[r]=1;
            v.push(l);
        }
    }
    //这时队列里头的元素的长度都为1
    while(!v.empty())
    {
        l=v.front();
        v.pop();
        for(i=0; i<16; i++)
        {
            if(num[i]==0)
                continue;
            l.nu[l.len]=i;
            l.len++;//这个地方自加1是在l这个点后依次加上每个数后在判断
            if(l.len>499)
                continue;
            int r=Mod(l);
            if(r==0&&l.len<500)
            {
                Print(l);
                return 1;
            }
            else
            {
                if(flag[r]==0&&l.len<499)
                {
                    flag[r]=1;
                    v.push(l);
                }
            }
            l.len--;//这个地方减1还是保持l这个点的长度变为原来的长度(这样就相当于用这个点向四周扩散)
        }
    }
    return 0;
}
int main()
{
    int t,i,j,m;
    char dd;
    scanf("%d",&t);
    while(t--)
    {
        memset(num,0,sizeof(num));
        memset(flag,0,sizeof(flag));
        scanf("%d%d%d",&N,&C,&m);
        for(i=0; i<m; i++)
        {
            getchar();
            scanf("%c",&dd);
            if(dd>='A')
                num[dd-'A'+10]=1;
            else
                num[dd-='0']=1;
        }
        if(N==0)
        {
            if(num[0])
                printf("0\n");
            else
                printf("give me the bomb please\n");
            continue;
        }
        int aa=bfs();
        if(!aa)
            printf("give me the bomb please\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值