zoj3662(01背包+预处理)
2016-04-05 20:48
253 查看
链接:点击打开链接
题意:有K个正整数,和为N,最小公倍数为M,为有多少种可能的情况
代码:
题意:有K个正整数,和为N,最小公倍数为M,为有多少种可能的情况
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; const int MOD=1000000007; int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b); } int cal(int a,int b){ return a/gcd(a,b)*b; } int num[1005],lcm[1005][1005]; int dp[2][1005][1005]; int main(){ //dp[i][j][k]代表第i个物品,和为j,lcm为k的种数 int i,j,k,p,N,M,K,st,cnt,tmp; //因为不能开一个1000*1000*100的数组,因此可以将 for(i=1;i<=1000;i++) //i用滚动数组表示 for(j=i;j<=1000;j++) lcm[i][j]=lcm[j][i]=cal(i,j); //预处理出所有lcm的值 while(scanf("%d%d%d",&N,&M,&K)!=EOF){ st=cnt=0; for(i=1;i<=M;i++) //以M的因子作为物品 if(M%i==0) num[cnt++]=i;for(i=0;i<=N;i++) for(j=0;j<=M;j++) dp[st][i][j]=0; dp[st][0][1]=1; for(k=1;k<=K;k++){ st^=1; for(i=0;i<=N;i++) for(j=0;j<=M;j++) dp[st][i][j]=0; for(i=k-1;i<=N;i++){ //前k个数和至少是k-1 for(j=0;j<cnt;j++){ if(dp[st^1][i][num[j]]==0) continue; for(p=0;p<cnt;p++){ tmp=lcm[num[j]][num[p]]; if(num[p]+i>N||M%tmp!=0) continue; dp[st][i+num[p]][tmp]=(dp[st][i+num[p]][tmp]+dp[st^1][i][num[j]])%MOD; } } } } printf("%d\n",dp[st] [M]); } return 0; }
相关文章推荐
- 用eclipse打包jar的时候有外部jar包
- 设置UITabBarController的图片问题
- vs2015新建mvc的空模版项目
- java实现图的深度优先搜索算法
- 字符串
- 对AlertDialog的简单认识
- Hibernate缓存机制详解
- 欢迎使用CSDN-markdown编辑器
- WM_PAINT产生原因有2种(用户操作和API)——WM_PAINT和WM_ERASEBKGND产生时的先后顺序不一定(四段讨论)
- C++类中的静态成员变量和静态成员函数的作用
- 网易游戏在线笔试(电子数字+画线)
- 经典IPC问题
- linux常用头文件详解(转)
- oj问题 K: 成绩处理
- 图结构练习——BFSDFS——判断可达性
- Android常用UI之AlertDialog
- iOS开发之设置UINavigationBar的主题
- uml工具
- Android动态资源加载原理和应用
- 10分钟搭建 nginx +php +mysql(LNMP)此为线上环境配置专用