POJ 1426 Find The Multiple(背包方案统计)
Description
Input
Output
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(背包方案统计)的更多相关文章
- 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 ...
- 广搜+打表 POJ 1426 Find The Multiple
POJ 1426 Find The Multiple Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 25734 Ac ...
- POJ 1426 Find The Multiple --- BFS || DFS
POJ 1426 Find The Multiple 题意:给定一个整数n,求n的一个倍数,要求这个倍数只含0和1 参考博客:点我 解法一:普通的BFS(用G++能过但C++会超时) 从小到大搜索直至 ...
- POJ 1426 Find The Multiple(寻找倍数)
POJ 1426 Find The Multiple(寻找倍数) Time Limit: 1000MS Memory Limit: 65536K Description - 题目描述 Given ...
- POJ.1426 Find The Multiple (BFS)
POJ.1426 Find The Multiple (BFS) 题意分析 给出一个数字n,求出一个由01组成的十进制数,并且是n的倍数. 思路就是从1开始,枚举下一位,因为下一位只能是0或1,故这个 ...
- DFS/BFS(同余模) POJ 1426 Find The Multiple
题目传送门 /* 题意:找出一个0和1组成的数字能整除n DFS:200的范围内不会爆long long,DFS水过~ */ /************************************ ...
- POJ 1426 Find The Multiple (DFS / BFS)
题目链接:id=1426">Find The Multiple 解析:直接从前往后搜.设当前数为k用long long保存,则下一个数不是k*10就是k*10+1 AC代码: /* D ...
- POJ 1426 Find The Multiple(数论——中国同余定理)
题目链接: http://poj.org/problem?id=1426 Description Given a positive integer n, write a program to find ...
- 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 ...
随机推荐
- Ng-cloak解决angularJs中的闪烁问题
引言 上一篇博客写到了使用ng-bind指令解决页面显示{{express}}问题,这次我们来使用另一种方法解决一下. 在使用AngularJS开发评教移动端的时候,我们经常会看见在Chrome这类快 ...
- ClouderaManager启动NodeManager失败!报错Failed to initialize container executor
报错信息: 2016-07-27 10:53:14,102 WARN org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor: ...
- weblogic检查项
日常维护中,weblogic检查的几个项: 1.JVM: 如最大堆内存.最小堆内存. 2.GC回收: 查看jvm空闲内存变化情况,每次GC的回收情况:控制台可以强制垃圾回收,看看回收内存是否太小,如果 ...
- PowerShell实现基于SharePoint的网站HomePage Auto-Create Solution
*** HomePage Auto-Create Solution Monday, January 12, 2015 PS:该项目为公司项目,我还是给他的名字屏蔽掉吧,这是我用PowerShell ...
- multi-mechanize error: can not find test script: v_user.py问题
从github上下载,安装multi-mechanize,新建工程,运行工程报错. 环境: win7-x64, python 2.7 multi-mechanize can not find test ...
- 混合编程:error LNK2001: unresolved external symbol
Vs2006+matlab2010rb环境: 1:工具-选项-项目解决方案-VC++目录设置include和lib的路径 2:项目-属性-属性配置-链接器-输入-附加依赖项把库的名字添加进去 VIST ...
- Server 2008作为打印服务器的四大错误解决方案
http://os.51cto.com/art/201004/197322.htm http://os.51cto.com/art/201004/197322_1.htm http://os.51ct ...
- 添加信任站点和允许ActiveX批处理
有两种写法 1.如果是用IP reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMa ...
- JPA联合主键
联合主键也就是说需要多个字段才能确定数据库记录中的唯一一行.这样就需要多个字段一起,组成主键,也叫联合主键.例如飞机航线,我们需要知道飞机起飞的地点以及飞机降落的地点.所以需要飞机起飞的地点和降落的地 ...
- 移动H5功能设计反思 测试用例总结
一.线上页面滑动流畅性测试 1.减少长动画效果(影响流畅) 2.是否自动跳转或者还是让用户自己操作跳转需要推敲 二.buttom和页面滑动的选择(优劣) 部分手机本身就会滑动不灵敏,大部分时候其实用b ...