【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\) 数组可能变化有限次后,答案不再发生变化。

先考虑如何求美丽值。

题目中对于“相邻”的定义可以简化:

\[\frac{lcm(x,y)}{gcd(x,y)} =\frac{\frac{x\times y}{gcd(x,y)}}{gcd(x,y)}=\frac{x\times y}{gcd(x,y)\times gcd(x,y)} \]

显然只要 \(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;
}
posted @ 2021-01-12 11:58  Valk3  阅读(153)  评论(0编辑  收藏  举报