[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;
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2023-11-07 19:09:30
博客类型