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_{1leq i leq n }d_i)
给出 (q) 个询问,每次询问给出当前时间 (w),问当前数组 (a) 的美丽值。
思路
(w) 的范围这么大,考虑 (a) 数组可能变化有限次后,答案不再发生变化。
先考虑如何求美丽值。
题目中对于“相邻”的定义可以简化:
显然只要 (x imes y) 是平方数,它俩就“相邻”。
如果(x imes y)是平方数,就要求 (x) 和 (y) 对应质因子的幂次奇偶性相同。
此时分别将 (x,y) 中偶数次幂的质因子删除掉,保留奇数次幂的质因子。
如果 (x = y),(x imes y) 是平方数,否则不是。
经过上述处理的数组 (a) 中,出现次数最多的数字的出现次数就是数组 (a) 的美丽值。
再看 (a) 发生变化对于其美丽值的影响。
前面说过只有 (x=y) 的时候,(x imes 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
", ans0);
} else {
printf("%d
", max(ans0, ans1 + even));
}
}
}
return 0;
}