题目大意:
需要你构造一个b数组。使得b数组中的所有元素互质。
而且使得b数组与a数组中的每个对应下标元素的差值和最小。
思路分析:
考虑到 a中所有元素都是 0 - 30.
所以b中的元素也只可能在 0 - 59.
因为如果b 选择60的话,结果和1是一样的,而且b序列中 1 可以重复出现很多次。
因为gcd (1,x) = 1。。
所以们首先把2 - 59中的所有素数处理出来,只有17个。
然后状压这些素数因子。
dp[i] [s] [0] 表示 递推到第 i 个位置 达到素数因子为s的状态下,第 i 个位置放的数。
dp[i] [s] [1] 表示。。。。。。。。。。。。。。。。。。。。。的最小值。
dp[i] [s] [2] 表示。。。。。。。。。。。。。。。。。。。。。的前驱,方便输出方案。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; int prime[20]; bool isprime(int x) { for(int i=2;i<x;i++) if(x%i==0)return false; return true; } int dp[105][1<<17][3]; int n; int a[105]; int Abs(int x) { return x>0?x:-x; } void print(int dep,int x) { if(dep==0)return; print(dep-1,dp[dep][x][0]); printf("%d ",dp[dep][x][2]); } int main() { int cnt=0; for(int i=2;i<=59;i++) if(isprime(i))prime[cnt++]=i; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int s; memset(dp,0x3f,sizeof dp); for(int i=0;i<(1<<17);i++)dp[0][i][0]=dp[0][i][1]=dp[0][i][2] = 0; for(int i=1;i<=n;i++) { for(int j=1;j<=59;j++) { s=0; for(int k=0;k<cnt;k++) { if(j%prime[k]==0) s|=(1<<k); } for(int st=1;st<(1<<17);st++) { if(!(st&s)) { if(dp[i-1][st][1]+Abs(a[i]-j)<dp[i][st|s][1]) { dp[i][st|s][2]=j; dp[i][st|s][1]=dp[i-1][st][1]+Abs(a[i]-j); dp[i][st|s][0]=st; } } } } } int ans=0x3f3f3f3f; int pos=0; for(int i=0;i<(1<<17);i++) { if(dp[n][i][1]<ans) { ans=dp[n][i][1]; pos=i; } } return 0; }
codeforces 453 B Little Pony and Harmony Chest (状压dp)
时间: 2024-10-01 22:46:21