POJ

题意:给出一个整数n,(1 <= n <= 200)。求出任意一个它的倍数m,要求m必须只由十进制的'0'或'1'组成,m不超过100位。

解题思路:首先大家应该会想到暴力枚举每一个m,但仔细考虑本题条件应该会涉及处理大数和超时的风险。而使用同余定理就可完全克服这个问题,再仔细分析搜索树就可进一步完全转换存储内容,从根本上解决大数问题。

话不多说,直接上例子,以n=6的bfs搜索过程为例:从最高位开始建立搜索树,逐层搜索每一位

          1

    0         1

  0     1       0     1

0  1  0  1  0  1  0  1

对6求余的结果

         1

    4         5

  4      5      2    3

4  5  2  3  2  3  0  1

即搜索出6的倍数为1110

观察搜索过程,设枚举答案为k(首位一定为1),下一层bfs得到10*k+0,10*k+1

   由同余定理知  (10*k+1)%6 = ((10*k)%6 + 1%6) %6=(((10%6)* (k%6))%6 + 1%6)%6

   如111%6=3,由同余定理知1110%6 =(111*10+0)%6 =(111%6) * (10%6) + 0)%6

***--------------所以我们只需要存下k对n求余的结果,便可层层bfs搜索了。那就只剩怎么得到真实答案了----------------***

此时想到二叉树的知识,对搜索树的节点从1开始编号

          1

    2         3

 

  4       5         6      7

 

8  9  10  11  12  13  14  15

我们发现每一个节点 i 的父节点为 i/2(向下取整),节点编号 i 对2求余的结果即与原搜索树内容相同(i的奇偶性决定该层选1/0)

  所以以树形int数组存储k%n,最终从下标 1 到下标 i (mod[i]%n ==0)的搜索路径上每一个下标的奇偶性就得到了最终结果

  例:n=6,mod[14] % 6 ==0,搜索路径下标1-3-7-14,最终结果为1-1-1-0

#define _CRT_SECURE_NO_WARNINGS  //VS编译器宏
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<vector>
#include<queue>
using namespace std;


int mod[2000005];//int为4B,给定内存为10000kB,1*10^7B/4B=25*10^5

int main() {
    int i, n, len;
    //C语言输入速度快,但加“cin.sync_with_stdio(false);”这行后cin的效率就与scanf相当了
    while (~scanf("%d", &n), n) {    //相当于while(scanf("%d",&n) != EOF , n)
        mod[1] = 1 % n;        //n为1时直接捕捉
        for (i = 2; mod[i - 1]; i++)
            mod[i] = (mod[i / 2] * 10 + i % 2) % n;
        i--;        //for循环结束条件为mod[i - 1]!=0,真实下标为i-1
        len = 0;
        while (i) {        //倒序存储编号
            mod[len++] = i % 2;
            i >>= 1;
        }
        while (len--)printf("%d", mod[len]);    //倒序输出正确答案
        printf("
");
    }
}
原文地址:https://www.cnblogs.com/zsh-notes/p/10500901.html