《 离 散 数 学 学 疯 以 后 》
【题目大意】
定义关系 (R) ,若 ( ext{lcm}(x,y)over gcd(x,y)) 为完全平方数,则 (x R y) 。
现给定长度为 (n) 的序列 (a) 。每次操作会将元素 (a_i) 替换为所有与之具有关系 (R) 的元素的乘积(包括它自己),即 (a_ileftarrow displaystyle prod_{a_i R a_j}a_j) 。
另外定义 (d_i) 表示与 (a_i) 具有关系 (R) 的元素的个数,定义序列的特征为 (d_i) 的最大值。
现有 (q) 个询问,每次询问给定 (w) ,输出 (w) 次操作后的序列的特征值。
【分析】
(ecause ext{lcm}(x,y)={xyover gcd(x,y)})
( herefore { ext{lcm}(x,y)over gcd(x,y)}={xyover gcd(x,y)^2})
(ecause gcd(x,y)^2) 为完全平方数
( herefore {xyover gcd(x,y)^2}) 为完全平方数 (Leftrightarrow) (xy) 为完全平方数
即若 (xy) 为完全平方数,则 (x R y)
不难发现,关系 (R) 具有以下三个特性:
- 自反性:(x^2) 为完全平方数 (Rightarrow) (x R x)
- 对称性:(x R y) (Rightarrow) (xy) 为完全平方数 (Rightarrow) (y R x)
- 传递性:(x R ywedge y R z) (Rightarrow) (xy,yz) 为完全平方数 (Rightarrow) (xzy^2=xycdot yz) 为完全平方数
(ecause y^2) 为完全平方数 ( herefore xz) 为完全平方数 (Rightarrow) (x R z)
因此关系 (R) 为等价关系,能将序列 (a) 分为若干等价类
因此,序列的特征等价于所有等价类大小的最大值;每次操作相当于将等价类内部的元素,替换成等价类所有元素的乘积
对于一个等价类 (P) ,由唯一质数分解定理,一定存在一个各质因子次数都不大于 (1) 的数 (r) ,使得 (forall xin Pleftrightarrow (exist nin Nwedge x=rcdot n^2))
证明:设 (exist x,yin P,nin Nwedge x=rcdot n^2)
(ecause xy=rycdot n^2) 为完全平方数,(n^2) 为完全平方数
( herefore ry) 为完全平方数
(ecause r) 各质因子次数不大于 (1)
( herefore y=rcdot m^2,min N)
因此各等价类可由各自的 (r) 作为其特征
对于一个等价类 (P) ,若 (|P|) 为偶数,则一次变化后,特征 (r) 变为 (1) ;若 (|P|) 为奇数,则一次变化后,特征 (r) 不变
因此,第一次操作前,序列的特征为最大的等价类
第一次操作后,原长度为偶数的等价类与原特征为 (1) 的等价类合并,原长度为奇数的等价类不变;序列的特征或为原长度为偶数的等价类大小,与原特征为 (1) 的等价类大小之和,或为长度为奇数的等价类大小
第二次操作及之后,等价类不再发生变化,答案不变
故仅需预处理第一次变化前的各等价类大小,即可预处理出第一次操作前后的答案,从而得出所有答案
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=3e5+10;
int N;
map<int,int> m;
inline void work(){
m.clear();
cin>>N;
for(int i=1;i<=N;i++){
int A;
cin>>A;
for(int j=2;j*j<=A;j++)//找出对应的 r
while(A%(j*j)==0) A/=j*j;
++m[A];//记录至等价类
}
int Ans0=0,Ansodd=0,Ans1=0;
for(auto e : m){
Ans0=max(Ans0,e.second);//等价类大小最大值,w=0时的答案
if(e.second&1) Ansodd=max(Ansodd,e.second);//等价类大小为奇数的最大值
else Ans1+=e.second;//第一次操作后,等价类大小为偶数的合并
}
if(m[1]&1) Ans1+=m[1];//特征为 1 的等价类还未合并
Ans1=max(Ans1,Ansodd);//w>0 时的答案
ll Q,W;
cin>>Q;
while(Q--&&cin>>W)
if(W) cout<<Ans1<<"
";
else cout<<Ans0<<"
";
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin>>T;
while(T--) work();
cout.flush();
return 0;
}