题意
给出 (n) 个数,满足 (frac{lcm(x,y)}{gcd(x,y)}) 为完全平方数的 (x,y) 称为相邻的。在每一秒,会发生以下操作:
- 每个数被所有和自己相邻数字(包括自己)的乘积所替换
- 设 (d_i) 为和数字 (a_i) 相邻的数字(包括自己)的数量
给出 (q) 组询问,查询第 (w) 秒时,数组中最大的 (d_i) 。
题目链接:https://codeforces.com/contest/1470/problem/B
分析
因为:
[lcm(x,y)=frac{x*y}{gcd(x,y)}
]
有:
[frac{lcm(x,y)}{gcd(x,y)}=frac{x*y}{gcd(x,y)^2}
]
因此,要使得 (frac{lcm(x,y)}{gcd(x,y)}) 为完全平方数,那么必然有 (x*y) 为完全平方数,即 (x*y) 的质因子的幂均为偶数。对所有数的质因子的幂进行模 (2) 的操作,假设 (x) 的一个质因子及其幂为 (p_i^{alpha_i}) 。可以发现,如果 (x) 和 (y) 的乘积为完全平方数,那么 (x) 和 (y) 的相同质因子的幂应该是相同的(模 (2) 情况下),因为偶数+偶数=偶数、奇数+奇数=偶数。因此,每个数可以用其幂模 (2) 后质因子的乘积代替,即 (x=p_1^{alpha_i\%2}*cdots *p_k^{alpha_k\%2}) 。 那么,在初始时刻,只要转化后的数相同,二者的乘积即为完全平方数,计数即可。在 (1s) 时,会有一个转化,即如果一个数出现了偶数次,那么这个数的各个质因子的幂会转化为 (0) 。此时重新计数,求出最大的 (d_i) ,即为 (1s) 及之后的答案。
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int M=1e5;
int n,cnt;
int prime[M];
bool vis[N];
map<ll,int>mp;
vector<ll>num;
void init()
{
cnt=0;
int maxn=1e6;
for(int i=2;i<=maxn;i++)
{
if(!vis[i])
prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=maxn;j++)
{
vis[prime[j]*i]=1;
if(i%prime[j]==0)
break;
}
}
}
void devide(int x)
{
ll res=1;
for(int i=1;i<=cnt&&1LL*prime[i]*prime[i]<=x;i++)
{
int cot=0;
while(x%prime[i]==0)
{
x/=prime[i];
cot++;
}
if(cot&1) res*=prime[i];
}
if(x>1)
res*=x;
num.pb(res);
mp[res]++;
}
int main()
{
int t;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
num.clear();
mp.clear();
for(int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
devide(a);
}
int q,ans1=0,ans2=0;
ll w;
for(int i=0;i<num.size();i++)
ans1=max(ans1,mp[num[i]]);
for(int i=0;i<num.size();i++)
{
if(mp[num[i]]%2==0||num[i]==1)
{
ans2+=mp[num[i]];
mp[num[i]]=0;
}
}
ans2=max(ans2,ans1);
scanf("%d",&q);
while(q--)
{
scanf("%lld",&w);
if(w==0) printf("%d
",ans1);
else printf("%d
",ans2);
}
}
return 0;
}