【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\)
思路
\(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\)
可知:變化 \(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;
}