這里題目給了幾個很顯眼的條件,ai限制在了1~30之間,由于可以bi無限選1這個數(shù),那么|ai-bi| 最大就是29了,意味著bi < 59的。
要求所有的bi互質(zhì),可以化為所有的bi分解出來的質(zhì)因數(shù)均不相同,bi < 59,有16個質(zhì)數(shù)。這里我們很容易聯(lián)想到狀態(tài)壓縮DP了。
用s表示當(dāng)前階段用了哪些質(zhì)因數(shù)的狀態(tài),例如 s = 3 = 11 代表目前狀態(tài)下使用了第一個和第二個質(zhì)因數(shù)。
很快我們就可以寫出狀態(tài)轉(zhuǎn)移方程:
f[i][s] = min(f[i-1][s^c[k]] + abs(a[i] - k))。 其中c[k]表示數(shù)字k使用了哪些質(zhì)因數(shù)。
#include#include #include #define M_max 60 #define N_max 123 #define inf 0x3f3f3f3f using namespace std; int p[N_max], c[M_max], a[N_max]; int f[N_max][1<<16], pre[N_max][1<<16][2]; int n, cnt, minnum, minpos; void prime() { for (int i = 2; i <= M_max; i++) { bool flag = false; for (int j = 2; j <= sqrt(i); j++) if (i%j == 0) { flag = true; break; } if (!flag) p[++cnt] = i; } for (int i = 1; i <= M_max; i++) for (int j = 1; j <= cnt; j++) if (i%p[j] == 0) c[i] |= 1 << (j-1); } void init() { prime(); scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); } void print(int x, int pos) { if (x == 0) return; print(x-1, pre[x][pos][0]); printf("%d ", pre[x][pos][1]); } void solve() { memset(f, inf, sizeof(f)); memset(f[0], 0, sizeof(f[0])); minnum = inf; for (int i = 1; i <= n; i++) for (int s = 0; s < (1<<16); s++) for (int k = 1; k <= M_max; k++) if ((s&c[k]) == c[k]) { int tmp = f[i-1][s^c[k]] + abs(a[i]-k); if (tmp < f[i][s]) { f[i][s] = tmp; pre[i][s][0] = s^c[k]; pre[i][s][1] = k; } } for (int s = 0; s < (1<<16); s++) if (f[n][s] < minnum) { minnum = f[n][s]; minpos = s; } print(n, minpos); } int main() { init(); solve(); }
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com