链接:
http://codeforces.com/contest/454/problem/D
题意:
给你一个a数组,求一个b数组,b中每两个数互质,并且最小。
题解:
状压DP,因为a<30,所以b中最大不会超过60,超过60就可以用1代替,想想59也是不需要的,所以除了1就剩下16个素数
状态压缩一下就可以,dp[i][j]表示到第i个数为止,已经用了哪些素数。代码改了好久,所以写的比较丑0.0
代码:
31 const int SN = 1 << 16; 32 int n; 33 int a[MAXN]; 34 int dp[MAXN][SN + 7]; 35 int s[60]; 36 PII route[MAXN][SN + 7]; 37 38 int prime[20] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53 }; 39 40 inline int getstate(int a) { 41 int u = 0; 42 for (int i = 0; i < 16; i++) { 43 while (a % prime[i] == 0) { 44 a /= prime[i]; 45 u |= (1 << i); 46 } 47 } 48 return u; 49 } 50 51 void print(int last, int id) { 52 if (id == 1) { 53 cout << route[id][last].second; 54 return; 55 } 56 print(route[id][last].first, id - 1); 57 cout << ' ' << route[id][last].second; 58 } 59 60 int main() { 61 ios::sync_with_stdio(false), cin.tie(0); 62 rep(i, 1, 60) s[i] = getstate(i); 63 cin >> n; 64 memset(dp, 0x3f, sizeof(dp)); 65 dp[0][0] = 0; 66 rep(i, 1, n + 1) cin >> a[i]; 67 rep(i, 1, n + 1) rep(j, 0, SN) rep(k, 0, 60) if ((j&s[k]) == 0) 68 if (dp[i][j | s[k]] > dp[i - 1][j] + abs(k - a[i])) { 69 dp[i][j | s[k]] = dp[i - 1][j] + abs(k - a[i]); 70 route[i][j | s[k]].first = j; 71 route[i][j | s[k]].second = k; 72 } 73 int ans = INF; 74 int last; 75 rep(j, 0, (1 << 16)) if (ans > dp[n][j]) { 76 ans = dp[n][j]; 77 last = j; 78 } 79 print(last, n); 80 cout << endl; 81 return 0; 82 }