POJ 2238 && HDU 4294

求一个数n的正整数倍m,在k进制下(poj 2238 只涉及10进制)表示时所需的不同数字数量最小

最后的答案不会有超过2个不同数字组成,理由如下:a,aa,aaa,aaaa,...中必定有两个模n同余(抽屉原理),两数相减就是n的倍数.接着判断只含一种数字能否满足答案,如果不行,再选2个数字进行广搜,找出最小的输出就可以了.

 

 

 

//poj 2283
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>

using namespace std;

const int maxn=65536;
int num[15];
int l,r,n;
int From[2*maxn],To[2*maxn],ans[2][2*maxn];
int flag[maxn];
int t;
int bfs(int a,int b)//广搜
{
    memset(flag,0,sizeof(flag));
    l=0,r=1;
    if(a==0)
    {
        l=2;
        To[2]=b;
        r=3;
        flag[0]=1;
        From[2]=0;
    }
    while(l<r)
    {
        if(flag[To[l]]==1)
        {
            l++;
            continue;
        }
        flag[To[l]]=1;
        To[r]=(To[l]*10+a)%n;
        From[r]=l;

        if(To[r]==0)
            break;
        r++;
        To[r]=(To[l]*10+b)%n;
        From[r]=l++;

        if(To[r]==0)
            break;
        r++;
    }
    int i;
    if(l<r)
    {
        for(i=0;r!=0;i++)
        {
            if(r&1)
                ans[t][i]=a;
            else
                ans[t][i]=b;
            r=From[r];
        }
        return i-1;
    }
    return -1;
}
int main()
{

    while(scanf("%d",&n),n)
    {
        num[0]=n;
        int c=0;
        for(int i=1;i<10;i++)
        {
            num[i]=1;
            int j=i;
            while(j%n!=0 && num[i]<n)
            {
                j=j*10%n+i;
                num[i]++;
            }
            if(num[i]<num[c])
                c=i;
        }
        if(c!=0)
        {
            for(int i=num[c];i>0;i--)
                printf("%d",c);
            printf("\n");
            continue;
        }
        int m=n;
        for(int i=0;i<10;i++)
        {
            for(int j=i+1;j<10;j++)
            {
                int ch=bfs(i,j);
                if(ch<m && ch!=-1)
                {
                    t=1-t;
                    m=ch;
                }
                else if(ch==m)
                {
                    for(int i=ch;i>=0;i--)
                    {
                        if(ans[t][i]<ans[1-t][i])
                        {
                            t=1-t;
                            break;
                        }
                        else if(ans[t][i]>ans[1-t][i])
                            break;
                    }
                }
            }
        }
        for(int i=m;i>=0;i--)
            printf("%d",ans[1-t][i]);
        printf("\n");


    }
    return 0;
}


//hdu 4294
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>

using namespace std;

const int maxn=65536;
int num[15];
int l,r,n,k;
int From[2*maxn],To[2*maxn],ans[2][2*maxn];
int flag[maxn];
int t;
int bfs(int a,int b)
{
    memset(flag,0,sizeof(flag));
    l=0,r=1;
    if(a==0)
    {
        l=2;
        To[2]=b;
        r=3;
        flag[0]=1;
        From[2]=0;
    }
    while(l<r)
    {
        if(flag[To[l]]==1)
        {
            l++;
            continue;
        }
        flag[To[l]]=1;
        To[r]=(To[l]*k+a)%n;
        From[r]=l;

        if(To[r]==0)
            break;
        r++;
        To[r]=(To[l]*k+b)%n;
        From[r]=l++;

        if(To[r]==0)
            break;
        r++;
    }
    int i;
    if(l<r)
    {
        for(i=0;r!=0;i++)
        {
            if(r&1)
                ans[t][i]=a;
            else
                ans[t][i]=b;
            r=From[r];
        }
        return i-1;
    }
    return -1;
}
int main()
{

    while(~scanf("%d%d",&n,&k))
    {
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        num[0]=n;
        int c=0;
        for(int i=1;i<k;i++)
        {
            num[i]=1;
            int j=i;
            while(j%n!=0 && num[i]<n)
            {
                j=j*k%n+i;
                num[i]++;
            }
            if(num[i]<num[c])
                c=i;
        }
        if(c!=0)
        {
            for(int i=num[c];i>0;i--)
                printf("%d",c);
            printf("\n");
            continue;
        }
        int m=n;
        for(int i=0;i<k;i++)
        {
            for(int j=i+1;j<k;j++)
            {
                int ch=bfs(i,j);
            
                if(ch<m && ch!=-1)
                {
                    t=1-t;
                    m=ch;
                }
                else if(ch==m)
                {
                    for(int i=ch;i>=0;i--)
                    {
                        if(ans[t][i]<ans[1-t][i])
                        {
                            t=1-t;
                            break;
                        }
                        else if(ans[t][i]>ans[1-t][i])
                            break;
                    }
                }
            }
        }
        for(int i=m;i>=0;i--)
            printf("%d",ans[1-t][i]);
        printf("\n");


    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值