[CF1103D] Professional layer
[题目链接]
http://codeforces.com/contest/1103/problem/D
[题解]
设 \(d = \gcd (a_1, a_2, \dots, a_n) = p_1^{s_1} p_2^{s_2} \dots p_m^{s_m}\) , 其中 \(p_{i}\) 为两两不同的质数。 因为 \(d <= 10 ^ {12}\) , 所以 \(m <= 11\)。
首先将每个 \(a_{i}\) 中不属于 \(p_{1} , p_{2} , ... p_{m}\) 的质数次幂去除。 剩下的元素最多有 \(M \leq 11958\) 个 (这个上界当且仅当 \(d = 2 * 3 * 5 * 7 * 11 * 13\))。
修改 \(a_{i}\) 的目标为 : 对于任意 \(1 \leq j \leq m\) , 都存在一个 \(a_{i}\) 满足 \(p_j \not| a_i\)。 为了最小花费 , ,显然对任一 \(d\) 的质因数 \(p_{j}\),我们只需要选择恰好一个 \(a_{i}\),将其修改为不被 \(p_{j}\) 整除即可。
因此我们最多用 \(M\) 个 \(a_{i}\)。
从而真正有用的 \(a_{i}\) 只有 \(e_{i}\) 最小的 \(m\) 个, 共有 \(mM\) 个。
不妨令 \(F[i][x][s]\) 表示前 \(i\) 个元素 , 修改了 \(x\) 个 , 且 \(s\) 描述了去除的质因子集合的最小花费。
那么有 : \(F[i][x][s] = \min_{t \subseteq s, t \models a_i} \{ F[i-1][x][s], F[i-1][x-1][s-t]+e_i \}.\)
时间复杂度 : \(O(n \log n+m M 2^m+m^2 3^m)\)
[代码]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
const int MN = 1e6 + 5;
const LL INF = 1e16;
LL K;
LL A[MN];
int C[MN];
int n;
LL li[30];
int cnt[30] , bak;
map < LL , vector < int > > mi;
map < LL , vector < LL > > ms;
int cl[1 << 11] , cb;
LL dp[12][1 << 11];
inline LL gcd(LL x , LL y) {
return y ? gcd(y , x % y) : x;
}
inline LL chkmin(LL &x , LL y) {
x = min(x , y);
}
inline void dfs(int S , int mask , LL now , const vector < LL > & vl) {
if (now > K) return;
if (S == bak) { cl[cb++] = mask; return; }
dfs(S + 1 , mask , now , vl);
dfs(S + 1 , mask | 1 << S , now * vl[S] , vl);
}
int main() {
scanf("%d%lld" , &n , &K);
LL g = 0;
for (int i = 1; i <= n; ++i)
scanf("%lld" , &A[i]) , g = gcd(g , A[i]);
for (int i = 1; i <= n; ++i)
scanf("%d" , &C[i]);
LL t = g;
for (int i = 2; (LL) i * i <= t; ++i)
if (t % i == 0) {
int cc = 0;
while (t % i == 0) t /= i , ++cc;
li[bak] = i , cnt[bak++] = cc;
}
if (t > 1) li[bak] = t , cnt[bak++] = 1;
for (int i = 1; i <= n; ++i) {
vector < LL > tx(bak , 1); t = 1;
for (int j = 0; j < bak; ++j)
while (A[i] % li[j] == 0)
A[i] /= li[j] , t *= li[j] , tx[j] *= li[j];
if (!mi.count(t)) ms[t] = tx;
mi[t].emplace_back(C[i]);
}
for (int i = 0; i <= bak; ++i)
for (int j = 0; j < 1 << bak; ++j)
dp[i][j] = INF;
dp[0][0] = 0LL;
int U = 1 << bak;
for (auto t : ms) {
dfs(0 , 0 , 1 , t.second);
vector < int > & lx = mi[t.first];
sort(lx.begin() , lx.end());
for (int T = 0; T < lx.size() && T < bak; ++T) {
for (int i = bak; i; --i) {
for (int j = 0; j < cb; ++j) {
int xc = U - 1 - cl[j];
for (int k = xc; ; k = (k - 1) & xc) {
if (dp[i - 1][k] != INF)
chkmin(dp[i][cl[j] | k] , dp[i - 1][k] + lx[T]);
if (!k) break;
}
}
}
}
cb = 0;
}
LL ans = INF;
for (int i = 0; i <= bak; ++i)
if (dp[i][U - 1] != INF)
chkmin(ans , dp[i][U - 1] * i);
if (ans == INF) ans = -1;
printf("%lld\n" , ans);
return 0;
}