CF1614D - Divan and Kostomuksha

大致思想

首先我们有结论:本质相同的数一定被放在一起。

比方说我们现在令 \(x\) 成为 \(a_1\),那么我们希望让剩下的所有数 \(y\) 都变成 \(\gcd(x,y)\),这样子势必会产生很多相同的数,我们就称这些数为“本质相同的数”(因为在 \(a_1\) 的限制下,这些数已经没有区别了)。因为 \(x\) 的因数个数有限,那么如果我们每加上一个数都让 \(\gcd\) 缩小一轮,大约不可能超过 \(20\) 次缩小。每次缩小我们令所有相同的数都放在一起,那么 \(dfs\) 深度将会非常浅。

那么如何达到这个效果呢?

做法

对于每一个数,跑出它的所有因数(包括它本身),令一个因数为 \(x\),则我们使 \(cnt[x]++\)

怎么跑出所有因数?使用欧拉筛。

nxt[1] = 1;
for(int i = 2; i < A; i++){
	if(!vis[i]){
		nxt[i] = 1;
		prime[++len] = i;
	}
	for(int j = 1; j <= len && i * prime[j] < A; j++){
		vis[i * prime[j]] = true;
		nxt[i * prime[j]] = i;
		if(i % prime[j] == 0){
			break;
		}
	}
}

vector<pair<int, int>> primefac;

void getfac_from_disasm(vector<int> &res, int i, int now){
	if(i == -1){
		res.push_back(now);
		return;
	}
	int mul = 1;
	for(int j = 0; j <= primefac[i].second; j++){
		getfac_from_disasm(res, i - 1, mul * now);
		mul *= primefac[i].first;
	}
}

void getfac(vector<int> &res, int x){
	primefac.clear();
	res.clear();
	map<int, int> mp;
	while(x != 1){
		mp[x / nxt[x]]++;
		x = nxt[x];
	}
	for(auto pr : mp)
		primefac.push_back(pr);
	getfac_from_disasm(res, (int) primefac.size() - 1, 1);
}

假设我们现在选出了第一个数 \(x\),那么我们枚举它所有的因数 \(y\)(不包括它本身),则与 \(x\) 本质相同的数的个数是 \(cnt[x]\),与 \(y\) 本质相同的数的个数是 \(cnt[y]-cnt[x]\)。依此类推,我们枚举 \(y\) 的所有因数 \(z\),则与 \(z\) 本质相同的数的个数是 \(cnt[z]-cnt[y]\)。因此我们很容易就可以写出 \(dfs\) 啦(别忘了记忆化)。

Code

#include <cstdio>
#include <vector>
#include <utility>
#include <cstring>
#include <map>
using namespace std;
const int A = 2e7 + 1, N = 2e5 + 1;

int n, a[N], cnt[A], prime[A], nxt[A], len;
bool vis[A];

long long ans[A], ANS;

vector<pair<int, int>> primefac;

void getfac_from_disasm(vector<int> &res, int i, int now){
	if(i == -1){
		res.push_back(now);
		return;
	}
	int mul = 1;
	for(int j = 0; j <= primefac[i].second; j++){
		getfac_from_disasm(res, i - 1, mul * now);
		mul *= primefac[i].first;
	}
}

void getfac(vector<int> &res, int x){
	primefac.clear();
	res.clear();
	map<int, int> mp;
	while(x != 1){
		mp[x / nxt[x]]++;
		x = nxt[x];
	}
	for(auto pr : mp)
		primefac.push_back(pr);
	getfac_from_disasm(res, (int) primefac.size() - 1, 1);
}

long long dfs(int x){
	if(ans[x] != -1) return ans[x];
	vector<int> facs;
	getfac(facs, x);
	facs.pop_back();
	for(auto y : facs)
		ans[x] = max(ans[x], dfs(y) + 1ll * (cnt[y] - cnt[x]) * y);
	return ans[x];
}

int main(){
	memset(ans, 0xff, sizeof(ans));
	ans[1] = 0;
	nxt[1] = 1;
	for(int i = 2; i < A; i++){
		if(!vis[i]){
			nxt[i] = 1;
			prime[++len] = i;
		}
		for(int j = 1; j <= len && i * prime[j] < A; j++){
			vis[i * prime[j]] = true;
			nxt[i * prime[j]] = i;
			if(i % prime[j] == 0){
				break;
			}
		}
	}
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
		vector<int> facs;
		getfac(facs, a[i]);
		for(auto x : facs)
			cnt[x]++;
	}
	for(int i = 1; i <= n; i++)
		ANS = max(ANS, 1ll * cnt[a[i]] * a[i] + dfs(a[i]));
	printf("%lld", ANS);
	return 0;
}
posted @ 2021-11-27 11:53  SpaceJellyfish  阅读(202)  评论(0)    收藏  举报