CF1103D Professional layer

CF1103D Professional layer

好题。

首先考虑分解质因数,对于每个有重质因数,找一些数将指数消成 00

好像分解不了那么多?发现有效质数集只能是 gcd\gcd,且不同质因子个数最多 1111 个。

状压就行了,记 fi,jf_{i,j} 表示选 ii 个数,消了 jj 的质数集合的最小花费。

注意到每次选一个数必定消掉一个新的质数,故第一维大小只有 mm,即最多选 mm 个数,所以每种数都保留最便宜的 mm 个。(记与能取得最大 gcd\gcd 的倍数的相同的 aia_i 为一类数)

暴力发现 mm 个质数所有的指数幂组合方式最多 1200012000 个,记为 NN

所以我们首先枚举组合方式,内层嵌套枚举对应的最便宜的 mm 的花费。

转移时先枚举选几个数,当前消的状态,以及准备消哪些质数。

时间复杂度 O(Nm23m)\mathcal O(Nm^23^m)

#include <cstdio>
#include <vector>
#include <unordered_map>
#include <cstring>
#include <algorithm>

typedef long long ll;

#define ha putchar(' ')
#define he putchar('\n')

inline ll read() {
	ll x = 0;
	char c = getchar();
	while (c < '0' || c > '9')
		c = getchar();
	while (c >= '0' && c <= '9')
		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}

inline void write(ll x) {
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + 48);
}

const int _ = 1e6 + 1;

int n, m;

ll k, f[12][1 << 11], ans = 1e18;

std::pair<ll, ll> c[_];

std::vector<ll> a, d;

std::unordered_map<ll, std::vector<ll>> mp;

ll gcd(ll a, ll b)
{
	return b ? gcd(b, a % b) : a;
}

signed main() {
	n = read(), k = read();
	ll nw = 0;
	for (int i = 1; i <= n; ++i) c[i].first = read(), nw = gcd(nw, c[i].first);
	for (int i = 1; i <= n; ++i) c[i].second = read();
	if (nw == 1) return write(0), he, 0;
	for (int i = 2; 1ll * i * i <= nw; ++i)
		if (!(nw % i)) {
			d.emplace_back(i);
			while (!(nw % i)) nw /= i;
		}
	if (nw != 1) d.emplace_back(nw);
	m = d.size();
	for (int i = 1; i <= n; ++i) {
		ll z = 1;
		for (ll j : d)
			while (!(c[i].first % j)) c[i].first /= j, z *= j;
		mp[z].emplace_back(c[i].second);
	}
	memset(f, 2, sizeof f);
	f[0][0] = 0;
	for (auto t : mp) {
		sort(t.second.begin(), t.second.end());
		a.clear();
		for (int i = 0; i < (1 << m); ++i) {
			ll z = 1, nw = t.first;
			for (int j = 0; j < m; ++j)
				if (i & (1 << j)) while (!(nw % d[j])) nw /= d[j], z *= d[j];
			a.emplace_back(z);
		}
		for (ll r : t.second) {
			bool flg = 0;
			for (int i = m - 1; i >= 0; --i)
				for (int j = 0; j < (1 << m); ++j) {
					int tmp = (1 << m) - j - 1;
					for (int p = tmp; p; p = (p - 1) & tmp)
						if (a[p] <= k && f[i + 1][j | p] > f[i][j] + r)  f[i + 1][j | p] = f[i][j] + r, flg = 1;
				}
			if (!flg) break;
		}
	}
	for (int i = 1; i <= m; ++i) ans = std::min(ans, f[i][(1 << m) - 1] * i);
	write(ans > 1e12 ? -1 : ans), he;
	return 0;
}
posted @ 2022-08-11 20:13  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源