题意
传送门 Codeforces 1325E Ehab’s REAL Number Theory Problem
题解
若任一元素存在为完全平方数的因子,则约去这些因子对答案没有影响;因为完全平方数除一个为完全平方数的因子,仍是完全平方数。由于任意元素至多存在 7 7 7 个因子,故约去完全平方数因子后,任意元素只可能为 1 , p , p q 1,p,pq 1,p,pq,其中 p , q p,q p,q 为素数。
将任意元素建模为边,即上述三种形式分别对应 1 − 1 , 1 − p , p − q 1-1,1-p,p-q 1−1,1−p,p−q。此时问题转化为取一组最小的边集,使边集的所有端点都经过偶数次;即求图中最小环。
边权为 1 1 1 的图上求最小环,可以通过构造 B F S BFS BFS 树求解(利用了 B F S BFS BFS 树的非树边只可能连向同层或相邻两层的性质)。枚举 B F S BFS BFS 树的根节点 r t rt rt,即枚举最小环所经过的节点,单次 B F S BFS BFS 求出经过 r t rt rt 的最小环的大小;具体而言,对于每条非树边 ( u , v ) (u,v) (u,v),用 d s [ u ] + d s [ v ] + 1 ds[u]+ds[v]+1 ds[u]+ds[v]+1 更新答案,其中 d s [ u ] ds[u] ds[u] 代表 u u u 至 r t rt rt 的最短距离。
由于任意元素不大于 max { a i } \max\{a_i\} max{ai},则任一边的一个端点必小于等于 max { a i } \sqrt{\max\{a_i\}} max{ai},那么枚举这些端点即可。总时间复杂度 O ( max { a i } ln max { a i } n ) O(\frac{\sqrt{\max\{a_i\}}}{\ln \sqrt{\max\{a_i\}}}n) O(lnmax{ai}max{ai}n)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
#define pb push_back
typedef long long ll;
const int MAXN = 1E5 + 5, MAXA = 1E6 + 5, INF = 0x3f3f3f3f;
int N, A[MAXN];
set<int> fac[MAXA];
int prime[MAXA], minp[MAXA], pn;
vector<int> G[MAXA];
int ds[MAXA], par[MAXA];
int bfs(int s)
{
int res = INF;
ds[1] = INF;
rep(i, 0, pn) ds[prime[i]] = INF;
queue<int> q;
q.push(s);
ds[s] = 0;
while (q.size())
{
int u = q.front();
q.pop();
for (auto &v : G[u])
{
if (ds[v] == INF)
ds[v] = ds[u] + 1, par[v] = u, q.push(v);
else if (v != par[u])
res = min(res, 1 + ds[u] + ds[v]);
}
}
return res;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N;
rep(i, 0, N) cin >> A[i];
rep(i, 2, MAXA)
{
if (!minp[i])
prime[pn++] = i, minp[i] = i;
for (int j = 0, k; j < pn && (k = prime[j] * i) < MAXA; ++j)
{
minp[k] = prime[j];
if (minp[i] == prime[j])
break;
}
}
rep(i, 2, MAXA)
{
int p = minp[i];
fac[i] = fac[i / p];
if (fac[i].count(p))
fac[i].erase(p);
else
fac[i].insert(p);
}
rep(i, 0, N)
{
int sz = fac[A[i]].size();
int u, v;
if (sz == 0)
u = v = 1;
else if (sz == 1)
u = 1, v = *fac[A[i]].begin();
else
u = *fac[A[i]].begin(), v = *(++fac[A[i]].begin());
G[u].pb(v), G[v].pb(u);
}
int res = bfs(1);
rep(i, 0, pn)
{
int p = prime[i];
if (p * p >= MAXA)
break;
res = min(res, bfs(p));
}
cout << (res == INF ? -1 : res) << '\n';
return 0;
}