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. python map函数的使用

    python2 中的map函数返回列表 python3 中的map函数返回迭代器 >>>def square(x) : # 计算平方数 ... return x ** 2 ... & ...

  2. python的一些科学计算的包

    在安装numpy这类科学计算的包的时候,pip下载的东西有时候缺少一些东西. 可以到这里下载,根据提示信息,少哪个包,或者哪个包出现错误就安装哪个包. PIL到这里下载

  3. python学习笔记(19)--PTVS的安装

    说明: 1. 折腾了两天eclipse,pydev,好不容易都弄好了,发现不会建工程,建完工程打不开,老是提示工作空间里有隐藏文件什么的,网上查了说是把.project里面的name标签的名字改了就行 ...

  4. python学习笔记(14)--爬虫下载漫画图片修改版

    说明: 1. 2017.3.12,周六从中午吃完包子12点多折腾了一下午加一个晚上,试了4个网站的爬虫,发现都不能下载!甚至前几天测试能下载的都不能用了! 2. 到晚上发现煎蛋网的可以用了,立即试了下 ...

  5. iOS 为什么使用xcode8上传app包到appStore无法构建版本

    使用xcode8或者application loader上传代码包到AppStore提示上传成功,但是我们在iTunes Connect中的构建版本或者活动中看不到已上传的代码包.这个问题原因是:ap ...

  6. jquery超炫的列表筛选插件

    今天要为大家带来一款非常实用的jquery列表筛选插件,效果非常好.单击某项的时候动画筛选该项的列表.我们一起看下效果图: 在线预览   源码下载 我们一起看下实现的代码: html代码: <d ...

  7. Servlet入门(第一个Servlet的Web程序)

    新建maven项目,注意项目的类型 project名为ServletExample 点击Finish.建立maven项目完毕例如以下 生成后的文件夹没有java源代码文件夹.依照maven的约定,还要 ...

  8. 未在本地计算机上注册"Microsoft.Jet.OLEDB.4.0"

    答案一: 因为没有安装64位的Jet40驱动.可以到http://www.microsoft.com/downloads/zh-cn/details.aspx?FamilyID=c06b8369-60 ...

  9. 设置DatagridView的列头样式

    设置DataGridView.ColumnHeaderDefaultCellStyle的BackColor属性会发现没有效果.这是因为在启动了可视样式的时候,BackColor和ForeColor的值 ...

  10. Android——事件处理模型一(基于回调机制的事件处理)(转)

    Android平台的事件处理机制有两种,一种是基于回调机制的,一种是基于监听接口的,现介绍第一种:基于回调机制的事件处理.Android平台中,每个View都有自己的处理事件的回调方法,开发人员可以通 ...