【CodeForces】#694 D. Strange Definition
CodeForces #694 D. Strange Definition
题意
定义数字 \(x\) 和 \(y\) 是“相邻”的当且仅当 \(\frac{lcm(x,y)}{gcd(x,y)}\) 是一个平方数。
给定一个长度为 \(n\) 的数组 \(a\)。
每过一秒,数组 \(a\) 会发生变化:\(a_i\) 会变成数组 \(a\) 中与其“相邻”的所有数字的乘积。
定义 \(d_i\) 为数组 \(a\) 中与 \(a_i\) “相邻” 的数字个数。
定义数组 \(a\) 的美丽值为 \(max_{1\leq i \leq n }d_i\)
给出 \(q\) 个询问,每次询问给出当前时间 \(w\),问当前数组 \(a\) 的美丽值。
思路
\(w\) 的范围这么大,考虑 \(a\) 数组可能变化有限次后,答案不再发生变化。
先考虑如何求美丽值。
题目中对于“相邻”的定义可以简化:
显然只要 \(x\times y\) 是平方数,它俩就“相邻”。
如果\(x\times y\)是平方数,就要求 \(x\) 和 \(y\) 对应质因子的幂次奇偶性相同。
此时分别将 \(x,y\) 中偶数次幂的质因子删除掉,保留奇数次幂的质因子。
如果 \(x = y\),\(x\times y\) 是平方数,否则不是。
经过上述处理的数组 \(a\) 中,出现次数最多的数字的出现次数就是数组 \(a\) 的美丽值。
再看 \(a\) 发生变化对于其美丽值的影响。
前面说过只有 \(x=y\) 的时候,\(x\times y\)才是平方数
那么 \(a\) 数组发生变化时,\(a_i\) 变成了 \({a_i}^{d_i}\);
同样变化之后,对于 \(a_i\) 只保留奇数次幂的质因子。
如果 \(d_i\) 是偶数,\(a_i\) 就变成了 \(1\),否则还是 \(a_i\)。
如果又过了一秒,那么此时能变成 \(1\) 的 \(a_i\) 已经变成 \(1\) 了,不能变的还是不能变。
可知:变化 \(1\) 次和变化多次的答案是一样的。
因为只会有不是 \(1\) 的变成 \(1\);
只需判断变化后 \(1\) 的数量是否大于没变化之前的答案,二者输出较大值。
变化后 \(1\) 的数量为:
没变化之前出现次数为偶数的非 \(1\) 的数字+原本 \(1\) 的出现次数。
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
const ll inf = 0x3f3f3f3f;
const ll N = 1e6 + 10;
int arr[N], sign[N];
int vis[N], pri[N], tot;
void solve(int n)
{
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
sign[i] = 1;
pri[++tot] = i;
}
for (int j = 1; j <= tot; j++) {
if (i * pri[j] > n)
break;
vis[i * pri[j]] = pri[j]; //纪录最小的素因子
if (i % pri[j] == 0)
break;
}
}
}
int sum[N];
vector<int> vec;
int main()
{
solve(1000000);//欧拉筛
int T;
scanf("%d", &T);
while (T--) {
vec.clear();
int n;
scanf("%d", &n);
int ans0 = 0, ans1 = 0;//ans0 表示出现此处最多的数字的出现次数
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
int tmp = 1, j = 1;
while (arr[i] >= pri[j]) {//只保留奇数次幂质因子
int num = 0;
while (arr[i] % pri[j] == 0) {
num++;
arr[i] /= pri[j];
}
if (num % 2)
tmp *= pri[j];
j++;
if (sign[arr[i]]) {
tmp *= arr[i];
break;
}
}
vec.pb(tmp);
ans0 = max(ans0, ++sum[tmp]);
}
int even = 0;
for (int v : vec) {
if (v != 1) {
if (sum[v] % 2 == 0)//未变化时出现次数为偶数且非 1 的数字数量
even++;
} else {
ans1++;//未变化时 1 的数量
}
}
for (int v : vec) {
sum[v] = 0;
}
int q;
scanf("%d", &q);
while (q--) {
ll w;
scanf("%lld", &w);
if (w == 0) {
printf("%d\n", ans0);
} else {
printf("%d\n", max(ans0, ans1 + even));
}
}
}
return 0;
}