454D - Little Pony and Harmony Chest
思路:
状压dp,由于1的时候肯定满足题意,而ai最大是30,所以只要大于等于59都可以用1替换,所以答案在1到59之间
然后筛出1到58之间的质数,只有16个,把1到58的数的状态由这16个质数表示,如果整除这个质数则二进制中这一位为1,否则则为0
状态:dp[i][j]表示到第i个数为止选取的数的状态为j的最小差和
初始状态:dp[0][0]=0
状态转移:
dp[i+1][j|sta[k]]=min(dp[i+1][j|sta[k]],dp[i][j]+abs(k-a[i+1]))(j&sta[k]==0,1<=k<=58)
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int INF=0x3f3f3f3f; int sta[65]; int a[105]; int res[105]; int dp[105][(1<<16)+5]; int ans[105][(1<<16)+5]; int prime[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; int getsta(int x){ int ans=0; for(int i=0;i<16;i++){ if(x%prime[i]==0)ans|=1<<i; } return ans; } void dfs(int n,int s){ if(n==0)return ; res[n]=ans[n][s]; dfs(n-1,s^sta[res[n]]); } int main(){ ios::sync_with_stdio(false); cin.tie(0); for(int i=1;i<59;i++){ sta[i]=getsta(i); } int n; cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; mem(dp,INF); mem(ans,-1); dp[0][0]=ans[0][0]=0; for(int i=0;i<n;i++){ for(int j=0;j<(1<<16);j++){ if(ans[i][j]==-1)continue; for(int k=1;k<59;k++){ if(j&sta[k])continue; int s=j|sta[k]; if(ans[i+1][s]==-1||dp[i][j]+abs(k-a[i+1])<dp[i+1][s]){ dp[i+1][s]=dp[i][j]+abs(k-a[i+1]); ans[i+1][s]=k; } } } } int mn=INF,s=0; for(int i=0;i<(1<<16);i++){ if(dp[n][i]<mn){ mn=dp[n][i]; s=i; } } dfs(n,s); for(int i=1;i<=n;i++)cout<<res[i]<<" "; cout<<endl; return 0; }