Codeforces 454D Little Pony and Harmony Chest【思维+状压Dp+记录路径】好题!
来源:互联网 发布:党规党纪面前知敬畏守 编辑:程序博客网 时间:2024/06/06 14:27
题目大意:
给出长度为N的一个序列A,让我们找到一个等长度序列B,使得Σabs(Ai-Bi)最小,要求B数组中,任取两个数字的Gcd为1,如果存在多解,输出一个即可。
思路:
需要不断去想优化时间复杂度的一个题,蛮不错的。
①首先考虑,对于这样的一个数组B,其置为1的个数可以为无限个,因为任何数和1的gcd都一定是1.那么我们再根据Ai的数据范围(1~30)可以得知,我们对于Bi的取值范围,一定介于(1~59)之间,因为我们假设取了值60.那么是不如直接取1来的更优的(对于任何数来讲都是一定的)。
②我们既然界定了B数组的取值范围,那么接下来考虑这类问题的特性,既然提到了Gcd,那么我们也一定能够联想到素数。如果对于一个位子的取值为K的时候,我们知道,如果K%pi(pi表示某个素数)==0的话,我们之后的位子中,就不能再存在一个数字X,使得X%pi==0了。
所以我们对于当前特性,我们可以设定Dp【i】【j】表示我们dp过程进行到位子i,对于素数占用的情况为j的最优解。因为60以内的素数个数并不多(17个),所以我们接下来去状压dp即可。
③我们预处理出num【k】,表示我们数字k会占用的素数的二进制表示。那么对于状态转移方程不难写出(从当前状态转移到下一状态):
Dp【i+1】【j+num【k】】=min(Dp【i+1】【j+num【k】】,Dp【i】【j】+abs(k-a【i+1】));【需要保证(j&num[k])==0】;
过程维护一下即可,需要输出路径,我们再维护一个数组pre【i】【j】,表示转移到状态Dp【i】【j】的时候,最后拿取的数字。
然后逆序走一波就行了。
Ac代码:
#include<stdio.h>#include<string.h>#include<algorithm>#include<iostream>#include<vector>using namespace std;int n;int a[103];int dp[103][(1<<17)];int pre[103][(1<<17)];int su[17]= {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};int num[65];void init(){ int end=(1<<17); for(int i=0; i<=n; i++) { for(int j=0; j<end; j++) { dp[i][j]=0x3f3f3f3f; } } memset(num,0,sizeof(num)); for(int i=2; i<=60; i++) { for(int j=0; j<17; j++) { if((i%su[j])==0)num[i]+=(1<<j); } }}int main(){ while(~scanf("%d",&n)) { int end=(1<<(17)); init(); for(int i=1; i<=n; i++)scanf("%d",&a[i]); dp[0][0]=0; for(int i=0; i<n; i++) { for(int j=0; j<end; j++) { if(dp[i][j]!=0x3f3f3f3f) { if(dp[i][j]+abs(a[i+1]-1)<dp[i+1][j]) { dp[i+1][j]=dp[i][j]+abs(a[i+1]-1); pre[i+1][j]=1; } for(int k=2; k<=60; k++) { if((num[k]&j)==0) { if(dp[i][j]+abs(k-a[i+1])<dp[i+1][j+num[k]]) { dp[i+1][j+num[k]]=dp[i][j]+abs(k-a[i+1]); pre[i+1][j+num[k]]=k; } } } } } } int pos; int output=0x3f3f3f3f; for(int j=0; j<end; j++) { if(dp[n][j]<output) { pos=j; output=dp[n][j]; } } int level=n; vector<int>ans; while(level>0) { ans.push_back(pre[level][pos]); pos-=num[pre[level][pos]]; level--; } reverse(ans.begin(),ans.end()); for(int i=0;i<ans.size();i++) { printf("%d ",ans[i]); } printf("\n"); }}
阅读全文
0 0
- Codeforces 454D Little Pony and Harmony Chest【思维+状压Dp+记录路径】好题!
- Codeforces 454D Little Pony and Harmony Chest 状压DP
- CODEFORCES, 454D Little Pony and Harmony Chest
- Codeforces 453B Little Pony and Harmony Chest 状压dp
- codeforces 453 B Little Pony and Harmony Chest (状压dp)
- Codeforces 453B Little Pony and Harmony Chest 状压DP
- codeforces 453 B Little Pony and Harmony Chest (状压dp)
- 【DP】 codeforces 453B Little Pony and Harmony Chest
- Codeforces 453B Little Pony and Harmony Chest(状压)
- cf 状压dp Little Pony and Harmony Chest
- Codeforces Round #259 (Div. 1) B. Little Pony and Harmony Chest(状压dp)
- Codeforces Round #259 (Div. 2) D Little Pony and Harmony Chest
- Codeforces Round #259 (Div. 2) D. Little Pony and Harmony Chest
- Codeforces 453 B Little Pony and Harmony Chest(Round 259 div.1 B/div.2 D)
- codeforces 453B Little Pony and Harmony Chest
- Codeforces 453 B. Little Pony and Harmony Chest
- CodeForces 453B Little Pony and Harmony Chest
- codeforces 453B Little Pony and Harmony Chest (离散化+dp状态压缩)
- 第四周 项目六 多项式求和
- 周末总结
- openlayers4中闪烁点的实现
- Algorithm-week4
- Qt 之 模仿 QQ登陆界面——功能篇(一)
- Codeforces 454D Little Pony and Harmony Chest【思维+状压Dp+记录路径】好题!
- Java类初始化顺序
- Proving Equivalences HDU
- Pixhawk飞行模式的讨论
- 集合类
- Divisors POJ
- HDOJ2054(大数处理)
- C++常见面试题(一)C/C++区别 const用法
- 文件操作——File