[AGC003D] Anticube
题面
给定 $n$ 个数 $s_i$ ,要求从中选出最多的数,满足任意两个数之积都不是完全立方数。 $n\le 10^5$ , $s_i\le 10^{10}$ 。
题解
爆草评测机做法。对于每个数,把指数化简,模三等于 1 或 2 才是有价值的,就是一个至多长 15 的链(16 个质数乘在一起一定大过 $10^{10}$ )。把这些链放在 Trie 里,转移函数用 map
即可,pbds 有玄学错误。
统计答案时,有一些对偶链,一双对偶链只能取一个,取最大那个。
代码
const int N = 1e5 + 3, M = 9600;
inline ll Read() {
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
namespace Main {
int n, ans;
int pri[M], cnt;
bool vis[N];
void Euler () {
for (int i = 2; i <= N - 3; i++) {
if (!vis[i]) pri[++cnt] = i;
for (int j = 1; j <= cnt && i * pri[j] <= N - 3; j++) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
}
}
}
struct Trie {
int tot, root;
map<int, int> ch[N];
int ed[N];
bool vis[N], visnode[N];
void insert (int &p, int j, ll a) {
if (!p) p = ++tot;
if (a == 1) {
ed[p]++;
return ;
}
int tmp = 0, flag = 1;
for (; !tmp && j <= cnt; j++) {
for (tmp = 0; a % pri[j] == 0; a /= pri[j], tmp = (tmp + 1) % 3);
if (tmp != 0) {flag = 0;break;}
}
if (j > cnt && a > 1) {
insert (ch[p][j << 1], j, 1);
return ;
}
if (j > cnt && flag) {
ed[p]++;
return ;
}
insert (ch[p][j << 1 | (tmp - 1)], j + 1, a);
return ;
}
void query (int p, int q) {
visnode[p] = 1;
if (ed[p] && !vis[p]) {
if (q != -1) {
ans += max(ed[p], ed[q]);
vis[p] = vis[q] = 1;
} else {
ans += ed[p];
vis[p] = 1;
}
}
for (auto i: ch[p]) {
int _p = i.second, _q = 0;
int k = i.first;
if (q != -1) _q = ch[q][k ^ 1];
if (!_q) _q = -1;
query (_p, _q);
}
}
}t;
int main () {
Euler();
n = Read();
for (int i = 1; i <= n; i++) {
ll x = Read();
//puts("[]");
t.insert(t.root, 1, x);
}
// printf ("%d\n", t.tot);
// for (int i = 1; i <= n; i++) printf ("%d %d %d\n", i, has1[i] * 1, has2[i] * 1);
t.vis[t.root] = 1;
t.query(t.root, t.root);
// int genshin = 0;
// for (int i = 1; i <= t.tot; i++) if (t.vis[i]) genshin += t.ed[i];
// printf ("%d\n", genshin);
// genshin = 0;
// for (int i = 1; i <= t.tot; i++) genshin += t.ed[i];
// printf ("%d\n", genshin);
// printf ("%d \n", t.ed[t.root]);
// printf ("%d %d\n", max(ans1, ans2) + min(t.ed[t.root], 1), ans + min(t.ed[t.root], 1));
printf ("%d\n", ans + min(t.ed[t.root], 1));
return 0;
}
}
int main () {
// freopen("lovely.in", "r", stdin);
// freopen("lovely.out", "w", stdout);
// freopen(".out", "w", stdout);
Main::main();
return 0;
}
更优的代码
const int N = 2e5 + 5, t = 1e5;
inline ll Read() {
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
namespace Main {
ll n, m;
ll q = 2160, cnt, g, num, ans, gen;
ll a[N], p[N], b[N], c[N], h[N];
int zero;
ll vis[N], f[N];
map<ll, ll> s[N][2];
int main () {
scanf ("%lld", &n);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (; !a[n] && n; n--, zero++);
for(int i = 2; i <= t; i++) {
if(!vis[i]) {
vis[i] = 1;
p[++cnt] = i;
h[i] = 1;
}
if(i <= q) g = cnt;
for(int j = 1; j <= cnt && p[j]*i <= t; j++) vis[p[j]*i] = 1;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= g; j++) {
if(a[i] < p[j]*p[j]*p[j]) break;
if(a[i] % (p[j]*p[j]*p[j]) == 0) a[i] = a[i] / p[j] / p[j] / p[j], j--;
}
int z = 1, z2 = 1;
if(a[i] == 1) {
ans = 1;
continue;
}
for(int j = 1; j <= g; j++) {
if(a[i] % p[j] == 0) {
a[i] = a[i] / p[j];
z *= p[j];
if(a[i] % p[j] == 0) {
a[i] = a[i] / p[j];
z *= p[j];
z2 *= p[j];
} else z2 *= p[j] * p[j];
}
}
b[i] = z, c[i] = z2;
gen = sqrt(a[i]);
if(a[i] == 1) {
s[0][0][z]++;
if(s[0][0][z] == 1 && s[0][0][z2] == 0) f[i] = 1;
} else if(a[i] <= t && h[a[i]] == 1) {
s[a[i]][0][z]++;
if(s[a[i]][0][z] == 1 && s[a[i]][1][z2] == 0) f[i] = 1;
} else if(gen * gen == a[i]) {
s[gen][1][z]++;
if(s[gen][1][z] == 1 && s[gen][0][z2] == 0) f[i] = 1;
} else num++;
}
ans += num;
for(int i = 1; i <= n; i++) {
if(f[i] == 1) {
if(a[i] == 1)ans += max(s[0][0][b[i]], s[0][0][c[i]]);
else if(a[i] <= t && h[a[i]] == 1) ans += max(s[a[i]][0][b[i]], s[a[i]][1][c[i]]);
else gen = sqrt(a[i]), ans += max(s[gen][1][b[i]], s[gen][0][c[i]]);
}
}
printf ("%lld\n", ans + zero);
return 0;
}
}
int main () {
freopen("lovely.in", "r", stdin);
freopen("lovely.out", "w", stdout);
Main::main();
return 0;