思路:
数组用来存储所需要的素数(上界为
个数中最大的一个,计为
),用线性筛即可。我们发现,求每两个数的
的乘积我们可以把每个数质因数分解后单独考虑每个质因子的贡献。
考虑先用一个数组存下所有数出现的次数。然后将每个可能为
个数的质因子的次方存下来(上界还是maxx,也就是代码中的f数组),
里面存的是它是哪个质数的次方。然后我们从
到
去枚举一个
,如果
为
,说明不是质因子的次方,因为我们只需要枚举质因子,所有此时直接
掉,因为不会对答案产生任何贡献,然后用倍数法去看是当前
的的倍数的数有多少个,若有
个,说明我可以组合出
(计为p)对有
这个因子的二元组,此时对答案产生的新的贡献就是
。这里可能有些难理解,举个例子,比如当前要枚举
,之前的
和
都已经被统计过了,且都乘了
,也就是乘了
,所以当前的这个
我们只需要乘一个
即可。然后最后直接输出即可。注意一下
和
即可(开始我全开了
只有
分,
飞了)。
这是我改进后的代码(自认为较之前的好理解许多,可以参考一下):
#include<cstdio>
#include<algorithm>
#define maxn 1000007
#define mod 998244353
using namespace std;
int a[maxn],f[maxn],prime[maxn],cnt,n,maxx,ans=1;
bool vis[maxn];
inline int pls(int a, int b) {int m=a+b;return m<mod?m:m-mod;}
inline int dec(int a, int b) {int m=a-b;return m<0?m+mod:m;}
inline int mul(int a, int b) {return 1ll*a*b%mod;}
inline int fpow(int a, long long b) {
int ans=1;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans=mul(ans,a);
return ans;
}
inline void init() { //线性筛。
vis[0]=vis[1]=1;
for(int i=2;i<=maxx;++i) {
if(!vis[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=maxx;++j) {
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
int main() {
scanf("%d",&n);
for(int i=1,x;i<=n;++i) {
scanf("%d",&x);
++a[x],maxx=max(maxx,x);
}
init();
for(int i=1;i<=cnt;++i) {
long long j=prime[i]; //标记每个可能为n个数质因子的所有在给定范围的次幂。
while(j<=maxx) {
f[j]=prime[i];
j*=prime[i];
if(j>maxx) break;
}
}
for(int i=1;i<=maxx;++i) { //对每个质因子单独考虑统计答案即可。
if(!f[i]) continue;
int r=0;
for(int j=i;j<=maxx;j+=i) r+=a[j];
ans=mul(ans,fpow(f[i],1ll*r*(r-1)>>1));
}
return 0;
} 
京公网安备 11010502036488号