CF 453B状态压缩dp
2015-08-02 13:35
423 查看
题目链接http://codeforces.com/problemset/problem/453/B
题意:给你n个数(1<=n<=100),每个数分别是ai(1<=ai<=30),问你求一个数列bi,其中bi间的数两两的最大公约数为1(bi可能都是1),且使得
最小。
思路:既然bi可以全部取1,那么每个bi的取值必定不超过30 - 1 + 30 = 59。由此可知我们只要知道60以内的所有数的素因子,并用数位标记的方式表示,如果这个数包含第几个素因子,则在第几位标1(第0位素因子是2),最后再用状态压缩dp处理最小值。
其中dp[i][j],表示取到第i位数,已经取过的素因子用数位的方式表示出来是j的最小值,则它由dp[i - 1][j ^ mark(k)]递推过来,mark(k)表示数k在二进制上包含哪些素因子,j ^ mark(k)则是不包含mark(k)中素因子的状态。
因为还需要输出答案,所以要保存每一个状态的最优值是取哪个数获得的,另开一个数组记录这个数。
题意:给你n个数(1<=n<=100),每个数分别是ai(1<=ai<=30),问你求一个数列bi,其中bi间的数两两的最大公约数为1(bi可能都是1),且使得
最小。
思路:既然bi可以全部取1,那么每个bi的取值必定不超过30 - 1 + 30 = 59。由此可知我们只要知道60以内的所有数的素因子,并用数位标记的方式表示,如果这个数包含第几个素因子,则在第几位标1(第0位素因子是2),最后再用状态压缩dp处理最小值。
其中dp[i][j],表示取到第i位数,已经取过的素因子用数位的方式表示出来是j的最小值,则它由dp[i - 1][j ^ mark(k)]递推过来,mark(k)表示数k在二进制上包含哪些素因子,j ^ mark(k)则是不包含mark(k)中素因子的状态。
因为还需要输出答案,所以要保存每一个状态的最优值是取哪个数获得的,另开一个数组记录这个数。
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define FOR(i,a,b) for(int i = a;i <= b;i++) using namespace std; typedef long long ll; const int maxn = 75; const int INF = 0x3f3f3f3f; int n; int prime[maxn]; int is[maxn]; int ori[maxn]; int len = 0; int dp[102][1 << 17]; int bef[102][1 << 17]; void pre() { len = 0; for(int i = 2;i < maxn;i++) { if(!is[i]) { for(int j = i;j < maxn;j += i) { prime[j] = prime[j] | (1 << len);//搜索出60内每一个数的所有素因数 is[j] = 1;//并用数位的方式标记上,该数的第i位为1说明他的因子中存在第i位素数 } len++; } if(len > 16)break; } } int rec[maxn]; int main() { pre(); while(~scanf("%d",&n)) { for(int i = 1;i <= n;i++)scanf("%d",ori + i); mem(dp[0],0); //初始化dp for(int i = 1;i <= n;i++) { for(int k = 1;k <= 60;k++) { int x = (~prime[k]) & ((1 << 17) - 1);//举出数k不包含的素因数的为数 for(int s = x;;s = (s - 1) & x)//并从这些位数向下枚举,接下来即为数位dp if(dp[i][s | prime[k]] > abs(ori[i] - k) + dp[i - 1][s]) { dp[i][s | prime[k]] = abs(ori[i] - k) + dp[i - 1][s]; bef[i][s | prime[k]] = k;//保存当前值取了哪个数,用作答案输出 } else if(s == 0)break; } } int ans = 0; for(int i = 0;i < (1 << 17);i++)//<F9> if(dp [ans] > dp [i]) ans = i; for(int i = n;i >= 1;i--) { rec[i] = bef[i][ans]; ans = prime[bef[i][ans]] ^ ans;//向前找出所有的答案,即为bef[i][s | prime[k]]的逆运算 } for(int i = 1;i <= n;i++) { if(i > 1)printf(" "); printf("%d",rec[i]); } printf("\n"); } }
相关文章推荐
- 一款简单实用的jQuery图片画廊插件
- zoj 3348 Schedule 【最大流经典建模】 【好题】
- 数学+DP Codeforces Round #304 (Div. 2) D. Soldier and Number Game
- 项目开发中的反思
- ORA-02291: integrity constraint (SYSTEM.FK1170E5C5328E4352) violated 解决办法
- windows10镜像大全
- THINKPHP 验证码类在SAE上的使用
- 1382 沙子合并
- 在cocos2dx中,横版游戏关于相机移动的方式整理
- AJAX调用IIS发布的接口报错问题
- Lua简明入门实践(从"基"搞起)_(二)Lua基础语法
- 使用 spring web 时候 web.xml 的配置
- 7-8月acm训练第一发(数论与计算几何)
- Oracle分组函数笔记
- 常用类库StringBuilder
- poj 1459 网络流问题`EK
- Android开发编码规范导致的内存泄露问题
- POJ 2983 Is the Information Reliable? 信息可靠吗 (差分约束,spfa)
- 贪心 Codeforces Round #263 (Div. 2) C. Appleman and Toastman
- 如何在 Windows 7 的 IIS 上发布 webservice