B. Little Pony and Harmony Chest(状压dp)
考虑 b i ≥ 59 b_i \ge 59 bi≥59时, b i = 1 b_i=1 bi=1更优。
所以只需考虑 b i ≤ 59 b_i \le 59 bi≤59 。
又因为 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;
}