[ZOJ 3662] Math Magic (动态规划+状态压缩)
题目链接: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) )
于是被康神吐槽了。。
#include <bits/stdc++.h>
using namespace std; const int MOD = ;
int n,m,kk;
int a[],ptr;
int lcmn[][];
int dp[][][];
int ss[][][]; void getlcmn(){
for(int i=;i<;i++){
for(int j=;j<;j++){
lcmn[i][j] = i / __gcd(i,j) * j;
}
}
} int main(){
getlcmn();
while(scanf("%d%d%d",&n,&m,&kk)!=EOF){
ptr = ;
for(int i=;i*i<=m;i++){
if( m%i== ){
a[ptr++] = i;
if( i*i!=m ) a[ptr++] = m/i;
}
}
//for(int i=0;i<ptr;i++) printf("%d ",a[i]); puts("");
memset(dp,,sizeof(dp));
for(int i=;i<=min(m,n);i++) dp[][i][i] = ;
for(int i=;i<=kk;i++){
for(int j=;j<=n;j++){
for(int k=;k<=m;k++) dp[i&][j][k] = ;
for(int s=;s<ptr;s++){
if( j-a[s]>= ){
for(int t=;t<ptr;t++) {
if(lcmn[a[s]][a[t]]<=m) {
dp[i&][j][lcmn[a[s]][a[t]]] += dp[(i-)&][j-a[s]][a[t]];
dp[i&][j][lcmn[a[s]][a[t]]] %= MOD;
}
}
}
}
}
}
printf("%d\n",dp[kk&][n][m]);
}
return ;
}
想法一
当时听康神说所谓的正解,还真是没听懂,正巧昨天做了这道题: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]] )
正向递推
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <iterator>
#include <vector>
using namespace std;
typedef long long LL; int n,m,k;
int p[],h[],w[],v[],ptr;
int dp[][][<<];
const int MOD = ; void prime_factor(int x){
for(int i=;i*i<=x;i++){
while( x%i== ){
p[i]++;
x /= i;
}
}
if( x!= ) p[x] = ;
} void handle(int x){
w[++ptr] = x;
for(int i=;i*i<=x;i++){
int t = ;
while( x%i== ){
t ++;
x /= i;
}
if( t&&t==p[i] ) v[ptr] |= (<<(h[i]-));
}
if( x!=&&p[x]== ) v[ptr] |= (<<(h[x]-));
} int main(){
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
ptr = ;
memset(p,,sizeof(p));
memset(w,,sizeof(w));
memset(v,,sizeof(v));
memset(h,,sizeof(h));
prime_factor(m);
int sn = ;
for(int i=;i<;i++){
if( p[i] ) {
h[i] = ++sn;
}
}
for(int i=;i*i<=m;i++){
if( m%i== ) {
handle(i);
if( i*i!=m ) handle(m/i);
}
}
memset(dp,,sizeof(dp));
dp[][][] = ;
for(int j=;j<=k;j++){
for(int i=;i<=ptr;i++){
for(int k=;k<=n;k++){
for(int mask=;mask<(<<sn);mask++){
if( k+w[i]<=n&&(mask|v[i])<(<<sn) ){
dp[j][k+w[i]][mask|v[i]] = (dp[j][k+w[i]][mask|v[i]]+dp[j-][k][mask])%MOD;
}
}
}
}
}
printf("%d\n",dp[k][n][(<<sn)-]);
}
return ;
}
想法二
[ZOJ 3662] Math Magic (动态规划+状态压缩)的更多相关文章
- ZOJ 2563 Long Dominoes(状态压缩DP)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1563 题目大意:在h*w的矩阵里铺满1*3的小矩阵,共有多少种方法 ...
- [动态规划]状态压缩DP小结
1.小技巧 枚举集合S的子集:for(int i = S; i > 0; i=(i-1)&S) 枚举包含S的集合:for(int i = S; i < (1<<n); ...
- [POJ 2923] Relocation (动态规划 状态压缩)
题目链接:http://poj.org/problem?id=2923 题目的大概意思是,有两辆车a和b,a车的最大承重为A,b车的最大承重为B.有n个家具需要从一个地方搬运到另一个地方,两辆车同时开 ...
- POJ 1185 炮兵阵地(动态规划+状态压缩)
炮兵阵地 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原( ...
- ACM学习历程—HDU1584 蜘蛛牌(动态规划 && 状态压缩 || 区间DP)
Description 蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起 ...
- HDOJ-1074(动态规划+状态压缩)
Doing Homework HDOJ-1074 1.本题主要用的是状态压缩的方法,将每种状态用二进制压缩表示 2.状态转移方程:dp[i|(1<<j)]=min(dp[i|(1<& ...
- zoj 3471 Most Powerful(状态压缩dp)
Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These ato ...
- 动态规划状态压缩-poj1143
题目链接:http://poj.org/problem?id=1143 题目描述: 代码实现: #include <iostream> #include <string.h> ...
- 3.4 熟练掌握动态规划——状态压缩DP
从旅行商问题说起—— 给定一个图,n个节点(n<=15),求从a节点出发,经历每个节点仅一次,最后回到a,需要的最短时间. 分析: 设定状态S代表当前已经走过的城市的集合,显然,S<=(1 ...
随机推荐
- maven学习笔记(基本的命令和概念)
mvn创建新项目: mvn archetype:generate -DgroupId=org.sonatype.mavenbook.ch03 -DartifactId=simple -Dpackage ...
- shiro权限验证标签
实例: spring-shiro.xml /admin/repairType/index = roles["ROLE_ADMIN"] /admin/user=roles[" ...
- 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0
昨天修改了一个工具,编译后本机运行正常,但放到服务器上执行却不行,提示: message:GetOleDbSchemaTable requires an open and available Conn ...
- 项目ppt演讲与阶段性总结
☆车老师讲解PPT项目: 1.汉企0410天启网络公司 2.Ppt--画龙点睛 3.项目制作背景-->点到人心上,别一堆文字,别虚,点出1234 4.说话量化.具象化:明天下午5.00做完,做不 ...
- [转]谈谈select, iocp, epoll,kqueue及各种网络I/O复用机制
参考原文:再谈select, iocp, epoll,kqueue及各种I/O复用机制 一.I/O模型概述 介绍几种常见的I/O模型及其区别,如下: blocking I/O nonblocking ...
- HTML <div> 和 <span>
可以通过 <div> 和 <span> 将 HTML 元素组合起来. HTML 块元素 大多数 HTML 元素被定义为块级元素或内联元素. 编者注:“块级元素”译为 block ...
- MongoDB小型文档型数据库使用
MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中 ...
- 战胜忧虑<3>——学会接受不可避免的事实。
学会接受不可避免的事实. 对必然的事情愉快地承受,就像杨柳承受风雨,水接受一切容器,我们也要承受一切事实. 故事: 在美国庆祝陆军在北非获胜的那一天,我接到国防部送来的一封电报,我的侄儿——我最爱的一 ...
- 什么是SQLCLR与使用
原帖地址:http://www.cnblogs.com/hsrzyn/archive/2013/05/28/1976555.html 什么是SQLCLR SQL CLR (SQL Common Lan ...
- ASP.NET运行机制原理
ASP.NET运行机制原理 一.浏览器和服务器的交互原理 (一).浏览器和服务器交互的简单描述: 1.通俗描述:我们平时通过浏览器来访问网站,其实就相当于你通过浏览器去另一台电脑上访问文件一样,只不过 ...