题意:
定义如果两个数 x , y x, y x,y “相邻”,那么 l c m ( x , y ) g c d ( x , y ) \frac{lcm(x, y)}{gcd(x, y)} gcd(x,y)lcm(x,y) 是平方数,给定长度为 n n n 的数字数组 a a a,其中的每个元素 a i a_i ai 每一秒后都会被所有与 a i a_i ai 相邻(包括 a i a_i ai 自己)的数字的乘积替换,定义 d i d_i di 为与 a i a_i ai 相邻的数字的个数,则数组 a a a 的 b e a u t y beauty beauty 为 m a x ( d i ) max(d_i) max(di),给出 q q q 次询问,每次询问是一个数字 w w w,回答 w w w 秒后数组 a a a 的 b e a u t y beauty beauty 是多少。其中 1 ≤ n ≤ 3 ⋅ 1 0 5 1 \le n \le 3 \cdot 10^5 1≤n≤3⋅105, 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1≤ai≤106, 1 ≤ q ≤ 3 ⋅ 1 0 5 1 \le q \le 3 \cdot 10^5 1≤q≤3⋅105, 0 ≤ w ≤ 1 0 18 0 \le w \le 10^{18} 0≤w≤1018。
思路:
- 经过简单的变换,我们可以将 l c m ( x , y ) g c d ( x , y ) \frac{lcm(x, y)}{gcd(x, y)} gcd(x,y)lcm(x,y) 化为 x ⋅ y g c d ( x , y ) 2 \frac{x \cdot y}{gcd(x, y)^2} gcd(x,y)2x⋅y,即若 x x x 和 y y y 相邻是当且仅当 x ⋅ y x \cdot y x⋅y 为平方数。
- 定义 a l p h a i alpha_i alphai 为数字 p a l p h a i p^{alpha_i} palphai 能整除 x 的最大的 a l p h a i alpha_i alphai, 同理于 b e t a j beta_j betaj 对于 y,则若 p α i ⋅ p β j p^{\alpha_i} \cdot p^{\beta_j} pαi⋅pβj 为平方数时当且仅当 α i + β j \alpha_i + \beta_j αi+βj 是偶数,即 α i ≡ β j \alpha_i \equiv \beta_j αi≡βj(mod 2)。
- 对 x x x、 y y y 分别进行质因数分解后我们可得 x = p 1 α 1 ⋅ … ⋅ p k α k x =p_1^{\alpha_1} \cdot \ldots \cdot p_k^{\alpha_k} x=p1α1⋅…⋅pkαk, y = p 1 β 1 ⋅ … ⋅ p k β k y =p_1^{\beta_1} \cdot \ldots \cdot p_k^{\beta_k} y=p1β1⋅…⋅pkβk,根据 2,我们将 x x x、 y y y 分别替换为 x = p 1 α 1 m o d 2 ⋅ … ⋅ p k α k m o d 2 x = p_1^{\alpha_1\bmod2} \cdot \ldots \cdot p_k^{\alpha_k\bmod2} x=p1α1mod2⋅…⋅pkαkmod2, y = p 1 β 1 m o d 2 ⋅ … ⋅ p k β k m o d 2 y = p_1^{\beta_1\bmod2} \cdot \ldots \cdot p_k^{\beta_k\bmod2} y=p1β1mod2⋅…⋅pkβkmod2,那么经过这样的替换后若两个数相邻当且仅当 x 和 y 相等,原因如下: 由 2 我们可知,若 x x x 和 y y y 相邻,则 p 1 α 1 , … , p k α k p_1^{\alpha_1}, \ldots, p_k^{\alpha_k} p1α1,…,pkαk 和 p 1 β 1 , … , p k β k p_1^{\beta_1}, \ldots, p_k^{\beta_k} p1β1,…,pkβk 中每个都要满足 α i ≡ β i \alpha_i \equiv \beta_i αi≡βi,因为 p 1 , … , p k p_1, \ldots, p_k p1,…,pk 都为质数,因此若不满足上述条件则 x x x 和 y y y 必然某个质因子的指数不同,也就造成了 x x x 和 y y y 不同,反之若满足上述条件,则 x x x 和 y y y 必然 “相邻”。
- 将数组中的每个元素进行替换,然后将相同元素分为一组。(1) 若组中有偶数个元素,那么下一秒这些元素都将变为 1 1 1,原因是: 因为有偶数个元素,那么对于最终乘积 z = p 1 α 1 , … , p k α k z = p_1^{\alpha_1}, \ldots, p_k^{\alpha_k} z=p1α1,…,pkαk 中每个 α i \alpha_i αi(mod 2),都满足 α i = 0 \alpha_i = 0 αi=0,也就是 z = 1 z = 1 z=1。(2) 若组中有奇数个元素,则下一秒组中的这些元素都不变,原因类似于偶数情况。因为 1 和奇数组都不再改变,而偶数组都会变为 1,因此答案也就只有 0 0 0 秒时和 1 1 1 秒后这两种情况,因此 a n s 0 ans_0 ans0 为 0 0 0 秒时最大的组的大小,而因为 1 1 1 秒后数组中 1 的个数会增加,因此 a n s 1 ans_1 ans1 为一秒后 1 1 1 的个数和 a n s 0 ans_0 ans0 的最大值。
做法:
- 做法 1 : 由于 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1≤ai≤106 范围不大,因此我们可以预处理 1 1 1 ~ 1 0 6 10^6 106 所有数 a i a_i ai 变换后的值 h i h_i hi (先找出质因数,然后看质因数的指数模 2 2 2 后是否为 1 1 1,若为 1 1 1, h i h_i hi 乘上该质因数, h i h_i hi 初始值为 1 1 1),此时对于每个数 a i a_i ai,其质因数 j j j 循环条件为 j ∗ j ≤ a i j * j ≤ a_i j∗j≤ai,因为 a i a_i ai 是不断变化的( a i a_i ai 不断除质因数),因此处理每个数 a i a_i ai 的时间复杂度为 O ( l o g a i ) \mathcal{O}(loga_i) O(logai),注意如果最终 a i a_i ai 不为 1 1 1 的话表示最终的 a i a_i ai 为质因子,此时 h i h_i hi 还需要乘上 a i a_i ai。 A C AC AC 时间为 826 m s 826ms 826ms。
- 做法 2 (做法 1 的优化): 在找质因数时,我们可以首先筛出 2 2 2 ~ 1 0 6 10^6 106 的素数,然后用素数 p r i m e j prime_j primej 替代做法 1 1 1 中的 j j j。 A C AC AC 时间为 498 m s 498ms 498ms。
- 做法 3 : 先使用 E r a t o s t h e n e s Eratosthenes Eratosthenes 筛法预处理出 2 2 2 ~ 1 0 6 10^6 106 每个数的最小质因子 m i n p i minp_i minpi,复杂度为 O ( ∑ 质 数 p ≤ N N P ) = O ( N l o g l o g N ) \mathcal{O}(\sum_{质数p ≤ N} \frac{N}{P})=\mathcal{O}(NloglogN) O(∑质数p≤NPN)=O(NloglogN), 然后在线处理出每个 a i a_i ai 变换后的值 h i h_i hi,在线处理的过程如下: a i a_i ai 除以它的最小质因子 p p p 直到最小质因子不为 p p p,然后再除以新 a i a_i ai 的最小质因子,如此这个过程直到 a i a_i ai 不大于 1 1 1,处理每个 a i a_i ai 的时间复杂度为 O ( l o g a i ) \mathcal{O}(loga_i) O(logai)。 A C AC AC 时间为 358 m s 358ms 358ms。
AC Codes :
做法 2 (注释部分为做法 1):
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <assert.h>
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 2e5 + 6, M = 1e9 + 7, INF = 0x3f3f3f3f;
int main() {
//freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
const int MAX = (int) 1e6 + 5;
vector<int> prime(100000), vis(MAX);
int cnt = 0;
for (int i = 2; i < MAX; i++) {
if (!vis[i]) prime[cnt++] = i;
for (int j = 0; j < cnt && i * prime[j] < MAX; j++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
vector<int> h(MAX, 1);
for (int i = 1; i < MAX; i++) {
int tmp = i;
for (int j = 0; j < cnt && prime[j] * prime[j] <= tmp; j++) {
if (tmp % prime[j] == 0) {
int cnt = 0;
while (tmp % prime[j] == 0) {
tmp /= prime[j];
cnt++;
}
h[i] *= cnt % 2 ? prime[j] : 1;
}
}
if (tmp > 1) h[i] *= tmp;
}
// for (int i = 1; i < MAX; i++) {
// int tmp = i;
// for (int j = 2; j * j <= tmp; j++) {
// if (tmp % j == 0) {
// int cnt = 0;
// while (tmp % j == 0) {
// tmp /= j;
// cnt++;
// }
// h[i] *= cnt % 2 ? j : 1;
// }
// }
// if (tmp > 1) h[i] *= tmp;
// }
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
a[i] = h[a[i]];
}
sort(a.begin(), a.end());
int ans0 = 0, ans1 = 0;
for (int l = 0; l < n; ) {
int r = l;
while (r < n && a[l] == a[r]) {
r++;
}
ans0 = max(ans0, r - l);
if ((r - l) % 2 == 0 || a[l] == 1)
ans1 += r - l;
l = r;
}
ans1 = max(ans0, ans1);
int q;
cin >> q;
while (q--) {
ll w;
cin >> w;
cout << (w == 0 ? ans0 : ans1) << '\n';
}
}
return 0;
}
做法 3 :
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <assert.h>
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 1e6 + 6, M = 1e9 + 7, INF = 0x3f3f3f3f;
int main() {
//freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
vector<int> minp(N + 1);
for (int i = 2; i <= N; i++) {
if (minp[i] == 0) {
minp[i] = i;
for (int j = 2 * i; j <= N; j += i) {
if (minp[j] == 0) {
minp[j] = i;
}
}
}
}
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
int x = a[i];
a[i] = 1;
while (x > 1) {
int q = minp[x];
int cnt = 0;
while (minp[x] == q) {
cnt++;
x /= q;
}
if (cnt % 2 == 1) {
a[i] *= q;
}
}
}
sort(a.begin(), a.end());
int ans0 = 0, ans1 = 0;
for (int l = 0; l < n; ) {
int r = l;
while (r < n && a[l] == a[r]) {
r++;
}
ans0 = max(ans0, r - l);
if ((r - l) % 2 == 0 || a[l] == 1)
ans1 += r - l;
l = r;
}
ans1 = max(ans0, ans1);
int q;
cin >> q;
while (q--) {
ll w;
cin >> w;
cout << (w == 0 ? ans0 : ans1) << '\n';
}
}
return 0;
}