题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3662

之前写过这道题,结果被康神吐槽说代码写的挫。

的确,那时候想法太挫了。

题意:

给你三个数n,m,k。

问你存在多少个数列 a1,a2,...,ak,使得他们的和为n,他们的最小公倍数为m。

想法一:

因为 lcm(a1,a2,...,ak)=m,所以a1,a2,a3,...,ak都是m的约数。

因此预处理出来m的约数,记在w[i]里。

设计状态dp[i][j][k]代表有i个数的数列,和为j,最小公倍数为k的个数。

转移:dp[i][j][k] = sigma( dp[i-1][s][t] ) 其中 s+w[i] = j,lcm( t,w[i] ) = k

于是写成 dp[i][s+w[i]][lcm(t,w[i])] = sigma( dp[i-1][s][t] )

需要优化的部分较多,需要滚动数组,很容易TLE掉。

时间复杂度O( n*m*k*sqrt(n) )

于是被康神吐槽了。。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. const int MOD = ;
  5. int n,m,kk;
  6. int a[],ptr;
  7. int lcmn[][];
  8. int dp[][][];
  9. int ss[][][];
  10.  
  11. void getlcmn(){
  12. for(int i=;i<;i++){
  13. for(int j=;j<;j++){
  14. lcmn[i][j] = i / __gcd(i,j) * j;
  15. }
  16. }
  17. }
  18.  
  19. int main(){
  20. getlcmn();
  21. while(scanf("%d%d%d",&n,&m,&kk)!=EOF){
  22. ptr = ;
  23. for(int i=;i*i<=m;i++){
  24. if( m%i== ){
  25. a[ptr++] = i;
  26. if( i*i!=m ) a[ptr++] = m/i;
  27. }
  28. }
  29. //for(int i=0;i<ptr;i++) printf("%d ",a[i]); puts("");
  30. memset(dp,,sizeof(dp));
  31. for(int i=;i<=min(m,n);i++) dp[][i][i] = ;
  32. for(int i=;i<=kk;i++){
  33. for(int j=;j<=n;j++){
  34. for(int k=;k<=m;k++) dp[i&][j][k] = ;
  35. for(int s=;s<ptr;s++){
  36. if( j-a[s]>= ){
  37. for(int t=;t<ptr;t++) {
  38. if(lcmn[a[s]][a[t]]<=m) {
  39. dp[i&][j][lcmn[a[s]][a[t]]] += dp[(i-)&][j-a[s]][a[t]];
  40. dp[i&][j][lcmn[a[s]][a[t]]] %= MOD;
  41. }
  42. }
  43. }
  44. }
  45. }
  46. }
  47. printf("%d\n",dp[kk&][n][m]);
  48. }
  49. return ;
  50. }

想法一

当时听康神说所谓的正解,还真是没听懂,正巧昨天做了这道题:http://www.cnblogs.com/llkpersonal/p/4037686.html

于是今天早上就想起这个题目,也想了想“正解”。

由题意我们知道,m是a1,a2,...,ak的最小公倍数,因此,将a1,a2,a3,...,an质因数分解,取每一个质因数的最高次幂,然后乘起来就是m。

那么我们先对m进行质因数分解,然后划分状态,假设有sn个质因数,那么总状态数就是(1<<sn)-1个。

然后去分解m的因数,给每个因数定状态,如果说因数k的质因数的指数等于m的指数,那么就给该状态标1。记作v[i]

然后去跑完全背包。

定义状态dp[i][j][k][mask]代表数列有i个数,从前j个数里选,和为k,状态为mask。

状态转移:dp[i][j][k][mask] = sigma( dp[i-1][j-1][s][t] ) 其中s+w[i] = k , t|v[i]=mask

于是有dp[i][j][s+w[i]][t|v[i]] = sigma( dp[i-1][j-1][s][t] ) 对于每一个i,都相当于是一次独立的完全背包。

由于是完全背包,因此j维可以省掉。

于是化为

dp[j][s+w[i]][t|v[i]] = sigma( dp[j-1][s][t|v[i]] )

正向递推

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <map>
  6. #include <iterator>
  7. #include <vector>
  8. using namespace std;
  9. typedef long long LL;
  10.  
  11. int n,m,k;
  12. int p[],h[],w[],v[],ptr;
  13. int dp[][][<<];
  14. const int MOD = ;
  15.  
  16. void prime_factor(int x){
  17. for(int i=;i*i<=x;i++){
  18. while( x%i== ){
  19. p[i]++;
  20. x /= i;
  21. }
  22. }
  23. if( x!= ) p[x] = ;
  24. }
  25.  
  26. void handle(int x){
  27. w[++ptr] = x;
  28. for(int i=;i*i<=x;i++){
  29. int t = ;
  30. while( x%i== ){
  31. t ++;
  32. x /= i;
  33. }
  34. if( t&&t==p[i] ) v[ptr] |= (<<(h[i]-));
  35. }
  36. if( x!=&&p[x]== ) v[ptr] |= (<<(h[x]-));
  37. }
  38.  
  39. int main(){
  40. while(scanf("%d%d%d",&n,&m,&k)!=EOF){
  41. ptr = ;
  42. memset(p,,sizeof(p));
  43. memset(w,,sizeof(w));
  44. memset(v,,sizeof(v));
  45. memset(h,,sizeof(h));
  46. prime_factor(m);
  47. int sn = ;
  48. for(int i=;i<;i++){
  49. if( p[i] ) {
  50. h[i] = ++sn;
  51. }
  52. }
  53. for(int i=;i*i<=m;i++){
  54. if( m%i== ) {
  55. handle(i);
  56. if( i*i!=m ) handle(m/i);
  57. }
  58. }
  59. memset(dp,,sizeof(dp));
  60. dp[][][] = ;
  61. for(int j=;j<=k;j++){
  62. for(int i=;i<=ptr;i++){
  63. for(int k=;k<=n;k++){
  64. for(int mask=;mask<(<<sn);mask++){
  65. if( k+w[i]<=n&&(mask|v[i])<(<<sn) ){
  66. dp[j][k+w[i]][mask|v[i]] = (dp[j][k+w[i]][mask|v[i]]+dp[j-][k][mask])%MOD;
  67. }
  68. }
  69. }
  70. }
  71. }
  72. printf("%d\n",dp[k][n][(<<sn)-]);
  73. }
  74. return ;
  75. }

想法二

[ZOJ 3662] Math Magic (动态规划+状态压缩)的更多相关文章

  1. ZOJ 2563 Long Dominoes(状态压缩DP)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1563 题目大意:在h*w的矩阵里铺满1*3的小矩阵,共有多少种方法 ...

  2. [动态规划]状态压缩DP小结

     1.小技巧 枚举集合S的子集:for(int i = S; i > 0; i=(i-1)&S) 枚举包含S的集合:for(int i = S; i < (1<<n); ...

  3. [POJ 2923] Relocation (动态规划 状态压缩)

    题目链接:http://poj.org/problem?id=2923 题目的大概意思是,有两辆车a和b,a车的最大承重为A,b车的最大承重为B.有n个家具需要从一个地方搬运到另一个地方,两辆车同时开 ...

  4. POJ 1185 炮兵阵地(动态规划+状态压缩)

    炮兵阵地 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原( ...

  5. ACM学习历程—HDU1584 蜘蛛牌(动态规划 && 状态压缩 || 区间DP)

    Description 蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起 ...

  6. HDOJ-1074(动态规划+状态压缩)

    Doing Homework HDOJ-1074 1.本题主要用的是状态压缩的方法,将每种状态用二进制压缩表示 2.状态转移方程:dp[i|(1<<j)]=min(dp[i|(1<& ...

  7. zoj 3471 Most Powerful(状态压缩dp)

    Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These ato ...

  8. 动态规划状态压缩-poj1143

    题目链接:http://poj.org/problem?id=1143 题目描述: 代码实现: #include <iostream> #include <string.h> ...

  9. 3.4 熟练掌握动态规划——状态压缩DP

    从旅行商问题说起—— 给定一个图,n个节点(n<=15),求从a节点出发,经历每个节点仅一次,最后回到a,需要的最短时间. 分析: 设定状态S代表当前已经走过的城市的集合,显然,S<=(1 ...

随机推荐

  1. 网站首页title 里显示ico图标

    有两种实现方式 图片尺寸大小 第一种:直接做一个favicon.ico 图标放在项目的根目录里就行 第二种:在网页HEAD标记中添加如下代码:<HEAD> <LINK REL=”SH ...

  2. 【shell】nmap工具的使用

    NMap,也就是Network Mapper,是Linux下的网络扫描和嗅探工 具包,其基本功能有三个,一是探测一组主机是否在线:其次是扫描主机端口,嗅探所提供的网络服务:还可以推断主机所用的操作系统 ...

  3. 关于css中列表(ul ol)存在默认间距的问题

    一.总结: 有时候我们要给列表(ul ol 本身就是属于块级元素)的上表框或下边框设置颜色,如下: 但是在给内联块级元素(inline-block)的上表框或下边框设置颜色的时候,就没有这么简单: 在 ...

  4. wcf stream 不知道长度的情况下,读取stream

    http://bbs.csdn.net/topics/360163784 string filepath = @"http://ww4.sinaimg.cn/thumbnail/6741e0 ...

  5. Python基础教程【读书笔记】 - 2016/7/5

    希望通过博客园持续的更新,分享和记录Python基础知识到高级应用的点点滴滴! 第三波:第8章  异常 [总览]学习如何创建和引发自定义的异常,以及处理异常的各种方法. 为了能够处理异常事件,可以再所 ...

  6. 使用仓库管理器——Sonatype Nexus的九大理由

    目前有很多组织使用了一些工具依赖于Maven仓库,但他们并没有采用一个仓库管理器,对于这一点我十分惊讶.可能没人提出来这一点,没人站出来告诉别人使用一个仓库管理器能带来什么好处.我经常能从很多不使用M ...

  7. php实时输出内容能够

    web开发中有没有碰到需要适时的将结果输出到浏览器页面而不刷新整个页面的需求呢?当你在处理一个过程需要耗时很长,但你又需要适时的知道程序当前的处理状况的时候,该怎么办呢?下面就分享一下如何使用php及 ...

  8. datagridview 不显示行号的问题

    环境:C#,Winform 场景: 窗体上有两个tab页A.B,每个tab页上都有一个DatagridView.窗体加载后,显示tab A选项卡.序号正常显示,但点击B选项卡后,DatagridVie ...

  9. 【转】SVN服务器客户端以及环境的搭建和使用

    vss,cvs,svn三者都是版本控制工具 vss是锁定-编辑-解锁模式,svn虽然也支持锁定,但默认是修改-冲突-合并模式 vss的版本号对应的是单个文件,svn的版本号对应的是整个版本库 vss是 ...

  10. div+css之清除浮动

    当元素有浮动属性时,会对其父元素或后面的元素产生影响,会出现一个布局错乱的现象,可以通过清除浮动的方法来解决浮动的影响. 浮动的清理(clear): 值:none:默认值.允许两边都可以有浮动对象:l ...