B. Little Pony and Harmony Chest(状压dp)

考虑 b i ≥ 59 b_i \ge 59 bi59​时, b i = 1 b_i=1 bi=1更优。

所以只需考虑 b i ≤ 59 b_i \le 59 bi59

又因为 b b b数组两两互质。

即每个质因子只能被一个数使用。

≤ 59 \le 59 59的质因子只有 16 16 16个。

考虑状压dp。

d p [ i ] [ s ] dp[i][s] dp[i][s]表示前 i i i个数选择的状态为 s s s的最小值,同时再开个数组维护 p r e [ i ] [ s ] pre[i][s] pre[i][s]表示当前选择的数。输出答案就对 p r e pre pre数组回溯就可以了。

时间复杂度: O ( 2 16 × 60 n ) O(2^{16}\times 60n) O(216×60n)

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=110;
const int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};//16 count
int n,a[N],dp[N][1<<17],pre[N][1<<17],f[N];
void dfs(int x,int s){
	if(x>1)	dfs(x-1,s^f[pre[x][s]]);
	printf("%d ",pre[x][s]);
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=60;i++)	for(int j=0;j<16;j++)	if(i%p[j]==0)	f[i]|=(1<<j);
	memset(dp,0x3f,sizeof dp);	dp[0][0]=0;
	for(int i=1;i<=n;i++)
		for(int s=0;s<(1<<16);s++)
			for(int j=1;j<=58;j++) if(!(f[j]&s)){
				int val=dp[i-1][s]+abs(a[i]-j);
				if(val<dp[i][s|f[j]])	dp[i][s|f[j]]=val,pre[i][s|f[j]]=j;
			}
	int mi=1e9,s;
	for(int i=0;i<(1<<16);i++) if(dp[n][i]<mi) mi=dp[n][i],s=i;
	dfs(n,s);
	return 0;
}