给出一个长度为n的数组ai, 求
1≤i<j≤nmaxLCM(ai,aj)n≤105,ai≤105
Link
CF1285H
Pre-knowledge
维护一个集合S,支持下列操作:
插入/删除一个数x
查询集合中与x互质的数有多少个
每个操作的复杂度需均为O(σ0(x))
化式子,查询即要求:
====y∈S∑[(x,y)==1]y∈S∑d∣x,d∣y∑μ(d)y∈S∑d∣x∑μ(d)⋅[d∣y]d∣x∑μ(d)⋅y∈S∑[d∣y]d∣x∑μ(d)⋅cnt(d)其中cnt(d)表示集合中d的倍数的数的个数,显然cnt(d)可以在插入/删除时通过枚举约数维护,答案也可以直接枚举约数计算
所有操作的复杂度均为O(σ0(x))
Solution
LCM(ai,aj)=gcd(ai,aj)aiaj,显然枚举g,计算(ai,aj)=g的所有i,j中,aiaj的最大值
首先可以O(nlnn)直接枚举g的所有倍数x,然后判断原序列中是否存在x。这样可以得到一个新的序列bi,题目便转化为在b中找到一对i,j,使得(bi,bj)=1,且bibj最大
考虑如何将 Pre-knowledge 中的数据结构派上用场
将b数组降序排列,维护一个栈。设当前数字为 x ,只要栈中存在与 x 互质的数,就拿栈顶与 x 的乘积更新 ans ,然后弹掉栈顶,循环如此,最后把 x 入栈。因为比 x 更小的数乘上栈顶一定不优,而若栈顶与 x 并不互质,这样得到的值也一定会被覆盖掉,所以正确性是对的。
总复杂度O(i=1∑nσ02(i))
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
| #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <climits> #include <queue> #include <set> #include <cmath> #include <map> #include <bitset> #include <fstream> #include <tr1/unordered_map> #include <assert.h>
#define x first #define y second #define y1 Y1 #define y2 Y2 #define mp make_pair #define pb push_back #define DEBUG(x) cout << #x << " = " << x << endl;
using namespace std;
typedef long long LL; typedef pair <int, int> pii;
template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0; } template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; } template <typename T> inline T read () { T sum = 0, fl = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1; for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0'; return sum * fl; }
inline void proc_status () { ifstream t ("/proc/self/status"); cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) << endl; }
const int MAXN = 1e5;
int N = MAXN, A[MAXN + 5], Mu[MAXN + 5];
vector <int> G[MAXN + 5];
inline void Init () { for (int i = 1; i <= N; ++i) for (int j = i; j <= N; j += i) G[j].pb (i);
static bitset <MAXN + 5> Vis; static int prime[MAXN + 5];
Mu[1] = 1; for (int i = 2; i <= N; ++i) { if (!Vis[i]) { prime[++prime[0]] = i; Mu[i] = -1; }
for (int j = 1; j <= prime[0] && (LL) i * prime[j] <= N; ++j) { Vis[i * prime[j]] = 1; if (!(i % prime[j])) { Mu[i * prime[j]] = 0; break; } Mu[i * prime[j]] = -Mu[i]; } } }
namespace DS { int cnt[MAXN + 5];
inline void insert (int x) { for (int y : G[x]) ++cnt[y]; } inline void erase (int x) { for (int y : G[x]) --cnt[y]; }
inline int query (int x) { int ans = 0; for (int y : G[x]) ans += Mu[y] * cnt[y]; return ans; } }
LL ans;
inline void Solve () { Init (); for (int g = 1; g <= N; ++g) { static vector <int> vec; for (int i = g; i <= N; i += g) if (A[i]) vec.pb (i / g);
if (vec.size() == 0) continue;
static int stk[MAXN + 5], top;
for (int i = vec.size() - 1; i >= 0; --i) { while (top && DS :: query (vec[i])) Chkmax (ans, (LL) g * vec[i] * vec[stk[top]]), DS :: erase (vec[stk[top]]), --top; stk[++top] = i, DS :: insert (vec[i]); }
while (top) DS :: erase (vec[stk[top]]), --top; vec.clear(); }
cout << ans << endl; }
inline void Input () { int n = read<int>(); while (n--) { int x = read<int>(); A[x] = 1; Chkmax (ans, (LL) x); } }
int main () {
#ifdef hk_cnyali freopen("F.in", "r", stdin); freopen("F.out", "w", stdout); #endif
Input (); Solve ();
return 0; }
|