Description

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.

Sample Input

2
6
19
0

Sample Output

10
100100100100100100
111111111111111111

思路:

1. 抽象成背包, 把0,1 串具体化, 变成 1, 10, 100, 1000

这里有两个好处:

第一, 每个数字都是唯一的, 任何数字不是另一个数字的前导, 抽象成背包问题

第二, 任何01串都可以用上述的数字表示出来. 比如, 111 = 100 + 10 + 1, 1110 = 1000+ 111

上面这个技巧, 在背包问题的一个优化中讨论过. 非常巧妙

2. dp[i][j] 表示前 i 个(1, 10, 100... 10^i) 组成的数字模 n 的余数 j 的最小值, 当该最小值不存在时, dp[i][j] = 0

  比如, 当 n = 6 时, dp[1][4] = 10. dp[1][5] = 11. dp[2][2] = 110

3. dp[i][j] = min(dp[i-1][j], dp[i-1][r]+10^i), 其中 r 也是余数, 当 j 等于0 且 dp[i][j] 不等于 0 时, 得到解

  表示以 上一层 (i-1) 的余数 r 作为支点更新 dp[i][j], 原理是:

  已知 r = dp[i-1][r]%n

  dp[i][(r + 10^i)%N] = dp[i-1][r] + 10^i 其中 j = (r + 10^i)%N

4. (3) 的求解过程中每次求解 (10^i)%n 太过复杂, 可以根据模定理进行优化

  定理: (a%n + b%n)%n == (a+b)%n, (a%n * b%n)%n == (a*b)%n

  可以使用上述定理简化以减少计算量

  比如, 已知 10%6 == 4, 那么 100%6 == (10*10)%6 == (10%6*10%6)%6 == (4*10%6)%6 == (4%6*10%6)%6 == (4*10)%6 == 4

  1000%6 == (100*10)%6 == (100%6*10%6)%6 == (4*10%6)%6 == 4

总结:

1. 发现一个错误: 一样的代码, 返回不一样的结果. 原因: int 越界

        exp *= 10;
rem = (rem * 10) % n; // 模运算定理
printf("exp = %lld, rem = %d\n", exp,rem);

  返回的是 10, 4 (correct)

但是

        exp *= 10;
rem = (rem * 10) % n; // 模运算定理
printf("exp = %d, rem = %d\n", exp,rem);

  返回的总是 10, 0 (wrong)

2. 任意的01串转化为1, 10, 100... 的组合, 从而抽象为01背包. 同时使用了一个简化计算 10^i 的技巧, 使得3个小时才看懂50行代码

代码:

代码写的不能再精髓了, 我了解思路后开始码, 但改过来改过去, 越改越觉得下面的代码精髓

1. 初始化, dp[i][r] == 0 表示没有满足条件的数, 同时省去了 dp[0][0] 的赋值

2. 17, 18, 23, 24行的代码, 保证了 min

3. 21 行, r==0 时的特殊性, 只有 r=0 时, 才能增加一个值

#include <iostream>
using namespace std; const int MAXN = 210;
int n;
long long int dp[MAXN][MAXN];
/*
* dp[i][r] 表示前 i 个数组成的数字模 n 等于 r 的最小值
* dp[i][r] = min(dp[i-1][r], dp[i][r']+10^i) 以 r' 为支点更新 dp[i][r]
*/
long long int solve_dp() {
dp[0][1] = 1;
long long int rem = 1, exp = 1;
for(int i = 1; i < MAXN; i ++) {
exp = exp*10;
rem = (rem*10)%n;
for(int r = 0; r < n; r ++) // 继承
dp[i][r] = dp[i-1][r]; for(int r = 0; r < n; r ++) {
if(dp[i-1][r] || r == 0) { //r == 0 比较特殊, 唯一一个可能用于更新的状态的值, 即使 dp[i-1][r] = 0, 去求 dp[i][r] 仍是必要的
long long int newr = (r + rem)%n;
if(dp[i][newr] == 0)
dp[i][newr] = exp + dp[i-1][r]; // 首次更新, 保证了最小性
if(newr == 0)
return dp[i][0];
}
}
}
}
int main() {
freopen("E:\\Copy\\ACM\\测试用例\\in.txt", "r", stdin);
while(cin >> n && n != 0) {
if(n == 1)
cout << 1 << endl;
else
cout << solve_dp() << endl;
}
return 0;
}

  

update 2014年3月14日21:00:58

1. r = 0 时的特殊性. r = 0 的特殊性体现在 dp[i][0] = 0 和 余数为 0 的双重意义.  余数为 0 表示不存在某个数对 n 取模为 0. 而 dp[i][0] = 0 又起到了初始化的作用, 使得对于一个数, 比如 100, dp[i][100%n] = 0 + 100. 这个 0 就用 dp[i][0] 取代了, 相当于代码重用

POJ 1426 Find The Multiple(背包方案统计)的更多相关文章

  1. POJ 3093 Margaritas(Kind of wine) on the River Walk (背包方案统计)

    题目 Description One of the more popular activities in San Antonio is to enjoy margaritas in the park ...

  2. 广搜+打表 POJ 1426 Find The Multiple

    POJ 1426   Find The Multiple Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25734   Ac ...

  3. POJ 1426 Find The Multiple --- BFS || DFS

    POJ 1426 Find The Multiple 题意:给定一个整数n,求n的一个倍数,要求这个倍数只含0和1 参考博客:点我 解法一:普通的BFS(用G++能过但C++会超时) 从小到大搜索直至 ...

  4. POJ 1426 Find The Multiple(寻找倍数)

    POJ 1426 Find The Multiple(寻找倍数) Time Limit: 1000MS    Memory Limit: 65536K Description - 题目描述 Given ...

  5. POJ.1426 Find The Multiple (BFS)

    POJ.1426 Find The Multiple (BFS) 题意分析 给出一个数字n,求出一个由01组成的十进制数,并且是n的倍数. 思路就是从1开始,枚举下一位,因为下一位只能是0或1,故这个 ...

  6. DFS/BFS(同余模) POJ 1426 Find The Multiple

    题目传送门 /* 题意:找出一个0和1组成的数字能整除n DFS:200的范围内不会爆long long,DFS水过~ */ /************************************ ...

  7. POJ 1426 Find The Multiple (DFS / BFS)

    题目链接:id=1426">Find The Multiple 解析:直接从前往后搜.设当前数为k用long long保存,则下一个数不是k*10就是k*10+1 AC代码: /* D ...

  8. POJ 1426 Find The Multiple(数论——中国同余定理)

    题目链接: http://poj.org/problem?id=1426 Description Given a positive integer n, write a program to find ...

  9. POJ 1426 - Find The Multiple - [DP][BFS]

    题目链接:http://poj.org/problem?id=1426 Given a positive integer n, write a program to find out a nonzer ...

随机推荐

  1. 在Hive中执行DDL之类的SQL语句时遇到的一个问题

    在Hive中执行DDL之类的SQL语句时遇到的一个问题 作者:天齐 遇到的问题如下: hive> create table ehr_base(id string); FAILED: Execut ...

  2. Loadrunner监控windows系统“找不到网络路径”问题解决

    一.监控windows系统: 1.监视连接前的准备工作 1)进入被监视windows系统,开启以下二个服务Remote Procedure Call(RPC) 和Remote Registry Ser ...

  3. 【技术】正則表達式—匹配电话号码,网址链接,Email地址

    #pragma mark - 正则匹配电话号码.网址链接.Email地址 + (NSMutableArray *)addHttpArr:(NSString *)text { //匹配网址链接 NSSt ...

  4. GB2312汉字区位码、交换码和机内码转换方法 (ZT)

    GB2312汉字区位码.交换码和机内码转换方法 (ZT) 为了适应计算机处理汉字信息的需要,1981年我国颁布了GB2312国家标准.该标准选出6763个常用汉字(其中,一级常用汉字3755个,二级汉 ...

  5. JavaScript 深入理解作用域链

    第一步. 定义后:每个已定义函数,都有一个内在属性[scope],其对应一个对象的列表,列表中的对象仅能内部访问. 例如:建立一个全局函数A,那么A的[Scope]内部属性中只包含一个全局对象(Glo ...

  6. Hbase 学习(二)各种filter

    各种filter 今天的主题是Filter,hbase客户端查询的时候,自定义查询filter. 直接上例子吧,不多说别的了,第一个例子是RowFilter的. Scan scan = new Sca ...

  7. OC基础--常用类的初步介绍与简单使用之NSDate

    一.创建一个时间 NSDate *date = [NSDate date]; // 打印出的时间是0时区的时间(北京--东八区) NSLog(@"%@",date); 二.日期格式 ...

  8. php面试

    var_dump()的作用是什么,主要用来干什么?Thread safe 和 Non Thread Safe 有什么区别?(本人表示不会,从没看见过)用php 把 gbk 的编码的字符串转换成 utf ...

  9. hadoop job解决大数据量关联时数据倾斜的一种办法

    转自:http://www.cnblogs.com/xuxm2007/archive/2011/09/01/2161929.html http://www.geminikwok.com/2011/04 ...

  10. BCM_I2C函数更改

    版本:sdk-xgs-robo- 平台:BCM53344 应用:控制POE芯片 描述:POE控制芯片使用PD69200,使用i2c与其通信,每次需要发送15字节数据,并接受15字节的返回数据. 1.更 ...