Codeforces 454D - Little Pony and Harmony Chest

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;
}

 

posted @ 2018-01-28 22:28  Wisdom+.+  阅读(272)  评论(0编辑  收藏  举报