Codeforces 453B Little Pony and Harmony Chest:状压dp【记录转移路径】
题目链接:http://codeforces.com/problemset/problem/453/B
题意:
给你一个长度为n的数列a,让你构造一个长度为n的数列b。
在保证b中任意两数gcd都为1的情况下,使得 ∑|a[i]-b[i]|最小。
让你输出构造的数列b。
(1<=n<=100, 1<=a[i]<=30)
题解:
因为1<=a[i]<=30,所以有1<=b[i]<=60,此时才有可能最优。
因为b中任意两数gcd为1,所以对于一个质因子p[i]只会在一个b[i]中用到。
所以先处理出1到60这些数所要用到的质因子,状压存在数组f[i]中,第i位为1表示要用到质因子p[i]。
另外,这题中59这个质因子是用不到的。
因为它能构成的60以内的数只有59,然而对于最大的a[i]=30来说,b[i]选59和选1是等效的。
这样就只剩16个质因子了。否则用17个会被卡时间和空间。
然后开始状压dp。
表示状态:
dp[i][state] = min value
表示该构造b[i]了,质因子的状态为state,此时原式的最小值。
如何转移:
dp[i+1][state|(1<<j)] = min dp[i][state] + |a[i]-j|
枚举当前b[i]选了j,然后转移。
边界条件:
dp[0][0] = 0
ohters = INF
改构造b[0]了,此时一个质因子还没用过,原式初始为0。
找出答案:
枚举质因子状态state,显然最小的dp[n][state]为答案。
然而现在只是知道了原式能达到的最小值,并不知道构造出的b数列。
所以在转移的时候要记录下转移路径。
新开两个数组:
sel[i][state]:表示从上一步转移到这一步时,b[i-1]选了哪个数字
sta[i][state]:若状态(i,state)是由(i-1,pre)转移而来的,则sta[i][state]为pre的值。
所以每次转移的时候将路径和所选的数记录下来:
if(dp[i][state]+d < dp[i+1][nex])
{
dp[i+1][nex]=dp[i][state]+d;
sel[i+1][nex]=j;
sta[i+1][nex]=state;
}
然后从最终答案的那一步,一直往前一个状态跳,就能找出构造的b数列了。
AC Code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#define MAX_N 105
#define MAX_P 20
#define MAX_D 65
#define MAX_S ((1<<16)+50)
#define INF 1000000000 using namespace std; const int p[]={,,,,,,,,,,,,,,,}; int n;
int a[MAX_N];
int dp[MAX_N][MAX_S];
int sel[MAX_N][MAX_S];
int sta[MAX_N][MAX_S];
int f[MAX_D]; inline int abs(int x)
{
return x> ? x : -x;
} int get_f(int x)
{
int state=;
for(int i=;i<;i++)
{
while(x%p[i]==)
{
x/=p[i];
state|=(<<i);
}
}
return state;
} void cal_f()
{
for(int i=;i<=;i++)
{
f[i]=get_f(i);
}
} void cal_dp()
{
memset(dp,0x3f,sizeof(dp));
dp[][]=;
for(int i=;i<n;i++)
{
for(int state=;state<(<<);state++)
{
if(dp[i][state]<INF)
{
for(int j=;j<=;j++)
{
if(!(state&f[j]))
{
int nex=(state|f[j]);
int d=abs(a[i]-j);
if(dp[i][state]+d<dp[i+][nex])
{
dp[i+][nex]=dp[i][state]+d;
sel[i+][nex]=j;
sta[i+][nex]=state;
}
}
}
}
}
}
int ans=INF;
int now;
for(int state=;state<(<<);state++)
{
if(dp[n][state]<ans)
{
ans=dp[n][state];
now=state;
}
}
stack<int> stk;
for(int i=n;i>=;i--)
{
stk.push(sel[i][now]);
now=sta[i][now];
}
while(!stk.empty())
{
cout<<stk.top()<<" ";
stk.pop();
}
cout<<endl;
} int main()
{
cin>>n;
for(int i=;i<n;i++) cin>>a[i];
cal_f();
cal_dp();
}
Codeforces 453B Little Pony and Harmony Chest:状压dp【记录转移路径】的更多相关文章
- Codeforces Round #259 (Div. 2) D. Little Pony and Harmony Chest 状压DP
D. Little Pony and Harmony Chest Princess Twilight went to Celestia and Luna's old castle to resea ...
- M - Little Pony and Harmony Chest 状压dp
M - Little Pony and Harmony Chest 怎么感觉自己越来越傻了,都知道状态的定义了还没有推出转移方程. 首先这个a的范围是0~30 这里可以推出 b数组的范围 0~60 ...
- Codeforces 454D - Little Pony and Harmony Chest
454D - Little Pony and Harmony Chest 思路: 状压dp,由于1的时候肯定满足题意,而ai最大是30,所以只要大于等于59都可以用1替换,所以答案在1到59之间 然后 ...
- Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP
Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10061 ...
- Educational Codeforces Round 13 E. Another Sith Tournament 状压dp
E. Another Sith Tournament 题目连接: http://www.codeforces.com/contest/678/problem/E Description The rul ...
- Codeforces 1225G - To Make 1(bitset+状压 dp+找性质)
Codeforces 题目传送门 & 洛谷题目传送门 还是做题做太少了啊--碰到这种题一点感觉都没有-- 首先我们来证明一件事情,那就是存在一种合并方式 \(\Leftrightarrow\) ...
- 【状压dp】Hamiton路径
描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点 ...
- CF1103D Codeforces Round #534 (Div. 1) Professional layer 状压 DP
题目传送门 https://codeforces.com/contest/1103/problem/D 题解 失去信仰的低水平选手的看题解的心路历程. 一开始看题目以为是选出一些数,每个数可以除掉一个 ...
- Codeforces 279D The Minimum Number of Variables 状压dp
The Minimum Number of Variables 我们定义dp[ i ][ mask ]表示是否存在 处理完前 i 个a, b中存者 a存在的状态是mask 的情况. 然后用sosdp处 ...
随机推荐
- Sql效能优化总结(续)- sql语句优化篇
今晚继续进行Sql效能问题的分享,今天主要是一些具体的sql优化方法和思路分享,若看过后你也有其他想法,欢迎一起探讨,好了,进入今天的主题. 针对性地对一些耗资源严重的具体应用进行优化 出现效能问题时 ...
- Iwfu-GitHubclient使用
Git/GitHub介绍 GitHub是著名的项目托管平台,有关Git和GitHub的介绍參考以下链接: Git介绍 url=OlagjwbaAdSJ2pjckgJCLBYd-LFFTDBriRnLt ...
- 第一次接触solr的过程记录
1.以solr-4.6.0.tgz为例进行学习 2.第一步,看的是 tutorial.html(位于solr-4.6.0/docs目录),默认solr以jetty作为servlet容器 3.但是,如果 ...
- (转) 对svn分支合并类型和深度的理解
合并的工作是把主干或者分支上合并范围内的所有改动列出,并对比当前工作副本的内容,由合并者手工修改冲突,然后提交到服务器的相应目录里.如果当前工作副本是主干,则合并的范围是分支上的改动,如果工作副本是分 ...
- 【转】使用Python学习selenium测试工具
出处:https://my.oschina.net/u/1433482/blog/633231?fromerr=vaxqh9bn
- mysql 存储过程初探
使用存储过程好处在于: 1.隐藏敏感的算法,避免被正常的开发人员看到,把业务逻辑隐藏在数据库中,而非程序代码里 2.简化应用代码程序,放到数据库里肯定就对程序代码简化有好处了 3.不同的开发语言都可以 ...
- 生成n个元素的全排列 C实现
近期在准备复习算法设计的考试,下边记录一些,看笔记时突然想到的解法. 问题是这种 用递归实现 n 个元素的全排列. 当时老师给出的解答是 假定第i个元素 ri 放在首位,于是 f(r1,r2,-,rn ...
- Java 学习 day08
01-面向对象(多态-概念) package myFirstCode; /* 多态:可以理解为事务存在的多种体现形态. 人:男人,女人 动物:猫,狗 猫 x = new 猫(); 动物 x = new ...
- poj2421
Constructing Roads Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22048 Accepted: 93 ...
- EasyDSS点播与直播服务器软件-二次开发接口对接说明示列
EasyDSS流媒体服务器软件,提供一站式的转码.点播.直播.时移回放服务,极大地简化了开发和集成的工作.其中,点播版本主要包含:上传.转码.分发.直播版本,主要包含:直播.录像, 直播支持RTMP输 ...