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;
}

浙公网安备 33010602011771号