Codeforces 454D Little Pony and Harmony Chest【思维+状压Dp+记录路径】好题!
2017-09-29 20:52
573 查看
D. Little Pony and Harmony Chest
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Princess Twilight went to Celestia and Luna's old castle to research the chest from the Elements of Harmony.
A sequence of positive integers bi is
harmony if and only if for every two elements of the sequence their greatest common divisor equals 1. According to an ancient book, the key of the chest is a harmony sequence bi which
minimizes the following expression:
You are given sequence ai,
help Princess Twilight to find the key.
Input
The first line contains an integer n (1 ≤ n ≤ 100)
— the number of elements of the sequences a and b.
The next line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 30).
Output
Output the key — sequence bi that
minimizes the sum described above. If there are multiple optimal sequences, you can output any of them.
Examples
input
output
input
output
题目大意:
给出长度为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
[j]<output)
{
pos=j;
output=dp
[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");
}
}
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Princess Twilight went to Celestia and Luna's old castle to research the chest from the Elements of Harmony.
A sequence of positive integers bi is
harmony if and only if for every two elements of the sequence their greatest common divisor equals 1. According to an ancient book, the key of the chest is a harmony sequence bi which
minimizes the following expression:
You are given sequence ai,
help Princess Twilight to find the key.
Input
The first line contains an integer n (1 ≤ n ≤ 100)
— the number of elements of the sequences a and b.
The next line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 30).
Output
Output the key — sequence bi that
minimizes the sum described above. If there are multiple optimal sequences, you can output any of them.
Examples
input
5 1 1 1 1 1
output
1 1 1 1 1
input
5 1 6 4 2 8
output
1 5 3 1 8
题目大意:
给出长度为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
[j]<output)
{
pos=j;
output=dp
[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");
}
}
相关文章推荐
- Codeforces 803E Roma and Poker【Dp+记录路径】
- Codeforces 792C Divide by Three【Dp+记录路径】
- Codeforces 507E Breaking Good【最短路SPFA+Dp+记录路径】好题~~~
- Codeforces 41D Pawn【dp+记录路径】
- Password CodeForces - 126B [KMP+DP思维]
- Codeforces 214D Numbers【思维+Dp】
- hdu 5092 Seam Carving(DP+记录路径)
- POJ 1141 Brackets Sequence(记录路径的dp)
- Codeforces 426E Sereja and Two Sequences【思维+Dp+二分】好题!
- hdu1074 状态压缩dp 记录路径
- hdu 1160 dp (二维最长上升子序列 记录路径
- hdu1160 FatMouse's Speed 最长上升子序列以及记录路径 DP
- CodeForces 55D. Beautiful numbers (思维+数位DP)
- codeforces 721C. Journey 最长路记录路径
- hdu 5092 Seam Carving dp+记录路径
- CodeForces - 711C Coloring Trees(DP)(思维)
- 最大连续子段和+记录路径 【DP 初步】
- hdu1074 状态压缩dp 记录路径
- codeforces 41D Pawn (简单dp+路径打印)
- hdu 1160 dp (二维最长上升子序列 记录路径