E - Find The Multiple(巧用for循环搜索)

题目地址:https://vjudge.net/contest/422351#problem/E

题目描述:

Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.

Input
The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.
Output
For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.

题目大意:

给定一个数字n,输出一个由0和1组成的数字使其能够整除n。

Sample Input
2
6
19
0
Sample Output

10

100100100100100100

111111111111111111

一、题目简述

  这一题第一眼看到样例输出,显然是不是使用int就能够完全储存下来的,至于能否使用long long就把它做出来,我们需要进行考虑,并且这题更大的价值在于思考如果n的值变大的话,该如何进行搜索。

二、普通dfs

2-1、思路:

我们可以尝试使用打表的方式进行检验,最后发现在1 <= n <= 200的情况下,unsigned long long是可以储存下所有答案的,因此可以使用普通dfs过这道题。

2-2、代码:

inline void dfs(ull num,ull ans,ull k)
{
    if(flag) return ;
    if(num%ans==0) 
    {
        sum=num;
        flag=1;
        return ;
    }
    if(k==19) return;
    dfs(num*10,ans,k+1);
    dfs(num*10+1,ans,k+1);
}
int main()
{
    while(1)
    {
        read(n);
        if(0==n) break;
        flag=0;
        dfs(1,n,0);
        printf("%llu\n",sum);
     }
     return 0;
}

三、改进搜索

3-1、思路

上述方式只是基于本题的一种解。诚然,只要做出来的代码就是好代码,不过作为扩展,我们可以考虑一下如何将n的可解范围扩大。

首先,如果将某个数的二进制右移一位,在十进制的视角下就相当于在原数的基础上乘以10,在二进制下的右移一位等于原数字在十进制下乘以2。

例如:2的二进制是10,4的二进制是100。

既然如此,我们可以尝试枚举每一个数字的二进制,并将其转为只有1和0的十进制数字,这样一来,我们的搜索顺序就是从小到大的顺序,而不是像上种方法一样不断的乘以十。从某种意义上来说,这有点像是dp。

        for(i=1;;i++)
        {
            a[i]=a[i>>1]*10+i%2;
            if(a[i]%n==0) 
            {
                printf("%llu\n",a[i]);
                break;
            }
        }

3-2、利用取模性质扩大范围

可以看到,我们依然用了unsigned long long的大数字,并不能够实际优化多少,这个时候就要用到取模的性质了:

(a+b)%p=(a%p+b%p)%p、(a*b)%p=(a%p*b%p)%p、(a-b)%p=(a%p-b%p)%p

我来翻译一下这三个公式:“你尽管取模,最后余数有变化算我输.jpg”

如此我们就能够扩大范围了。

3-3代码:

int main()
{
    while(1)
    {
        read(n);
        if(0==n) break;
        for(i=1;;i++)
        {
            a[i]=(a[i>>1]*10+i%2)%n;
            if(a[i]==0) break;
        }
        int ans=i;
        int cnt=0;
        while(ans)
        {
            a[++cnt]=ans&1;
            ans>>=1;
        }
        
        for(cnt;cnt>=1;cnt--) printf("%d",a[cnt]);
        printf("\n");
    }
    return 0;
}

 

posted @ 2021-02-22 18:07  ztlsw  阅读(26)  评论(0编辑  收藏  举报