1. 程式人生 > 實用技巧 >【CodeForces】#694 D. Strange Definition

【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;
}