CF1285F Classical?

CF1285F Classical?

2900。

将所有 aia_i 的因子加入集合 SS,询问即

maxiSmaxjsij[gcd(i,j)=1]\max_{i\in S}\max_{j \in s}ij[\gcd(i,j)=1]

考虑二分答案,记为 lim\lim

判断即计算

iSjS[ijlim][gcd(i,j)=1][i<j]\sum_{i\in S}\sum_{j\in S}[ij\leq lim][\gcd(i,j)=1][i<j]

上述式子肯定是非严格单增的,且当取到最大值时,limlim 就是答案。

最大值就是

iSjS[gcd(i,j)=1][i<j]\sum_{i\in S}\sum_{j\in S}[\gcd(i,j)=1][i<j]

莫反呗,等价于。

p=1Vμ(p)di,iSdj,jS[ijlim][i<j]\sum_{p=1}^{V}\mu(p)\sum_{d|i,i\in S}\sum_{d|j,j\in S}[ij\leq lim][i<j]

先枚举外层 pp,再枚举 ii,找到 limi\leq \lfloor\frac{lim}{i}\rfloorjj,双指针维护即可。

时间复杂度 O(VlnVlog21010)\mathcal O(V\ln V\log_2 10^{10})

#include <bits/stdc++.h>

using namespace std;

#define int long long
typedef long long ll;

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

inline int read() {
	int 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 > 9)
		write(x / 10);
	putchar(x % 10 + 48);
}

const int _ = 1e5 + 10;

int n, cnt, res, mu[_], pr[_];

bitset<_> v, t;

vector<int> d[_];

void init()
{
	mu[1] = 1;
	for(int i = 2; i < _; ++i)
	{
		if(!v[i]) mu[pr[++cnt] = i] = -1;
		for(int j = 1; j <= cnt && i * pr[j] < _; ++j)
		{
			v[i * pr[j]] = 1;
			if(i % pr[j] == 0) break;
			mu[i * pr[j]] = -mu[i];
		}
	}
}

int check(int x)
{
	int ans = 0, p;
	for(int i = 1; i < _; ++i)
	{
		if(!mu[i]) continue;
		p = d[i].size() - 1;
		for(int k = 0; k < d[i].size(); ++k)
		{
			while(p > k && d[i][p] > x / d[i][k]) --p;
			if(p <= k) break;
			ans += mu[i] * (p - k);
		}
	}
	return ans;
}

signed main()
{
	init();
	n = read();
	for(int i = 1, x; i <= n; ++i)
	{
		x = read();
		for(int j = 1; j * j <= x; ++j)
			if(x % j == 0) t[j] = t[x / j] = 1;
	}
	for(int i = 1; i < _; ++i)
	{
		if(!t[i]) continue;
		for(int j = 1; j * j <= i; ++j)
			if(i % j == 0)
			{
				d[j].push_back(i);
				if(j == i / j) break;
				d[i / j].push_back(i);
			}
	}
	for(int i = 1; i < _; ++i) res += mu[i] * (d[i].size() * (d[i].size() - 1) / 2ll);
	int l = 1, r = 1e10, mid;
	while(l < r)
	{
		mid = (l + r) >> 1;
		if(check(mid) < res) l = mid + 1;
		else r = mid;
	}
	return write(l), he, 0;
}
posted @ 2022-08-21 09:21  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源