luogu P5221 Product
题面传送门
按照常见莫反套路先拆式子
\(\prod\limits_{i=1}^{N}{\prod\limits_{j=1}^{N}{\frac{i\times j}{gcd(i,j^2)}}}\)
\(\prod\limits_{i=1}^{N}{i^{2N}}\times \prod\limits_{i=1}^{N}{\prod\limits_{j=1}^{N}{\frac{1}{gcd(i,j)^2}}}\)
前面那个\(O(nlogn)\)直接可以求就只看后面那一部分。枚举\(gcd\)变为
\(\prod\limits_{d=1}^{N}{d^{\sum\limits_{i=1}^{N}{\sum\limits_{j=1}^{N}{[gcd(i,j)==d]}}}}\)
\(\prod\limits_{d=1}^{N}{d^{\sum\limits_{i=1}^{\frac{N}{d}}{\sum\limits_{j=1}^{\frac{N}{d}}{[gcd(i,j)==1]}}}}\)
然后变成\(\prod\limits_{d=1}^{N}{(\frac{1}{d})^{\sum\limits_{i=1}^{\frac{N}{d}}{\phi(i)}\times 2-1}}\)
这个东西线性筛筛出来然后费马小定理求逆元也能算。
注意到上面那个远大于\(mod\)可以用费马小定理减小常数。
时间复杂度\(O(nlogn)\)
code:
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db long double
#define N 1000000
#define eps (1e-14)
#define mod 104857601
using namespace std;
int n,pr[N+5],phi[N+5],ph,r;ll ans=1,now,tot;bitset<N+5> f;
I ll mpow(ll x,ll y){ll ans=1;while(y)(y&1)&&(ans=ans*x%mod),y>>=1,x=x*x%mod;return ans;}
int main(){
freopen("1.in","r",stdin);
re int i,j;scanf("%d",&n);
for(i=2;i<=n;i++){
if(!f[i]){pr[++ph]=i;phi[i]=i-1;}
for(j=1;j<=ph&&pr[j]*i<=n;j++){
f[pr[j]*i]=1;if(i%pr[j]==0){phi[pr[j]*i]=phi[i]*pr[j];break;}
phi[pr[j]*i]=phi[i]*phi[pr[j]];
}
}
for(i=1;i<=n;i++) ans=ans*i%mod;ans=mpow(ans,2*n);
for(i=n;i;i--){
for(;r<=n/i;r++) tot+=phi[r];tot=tot%(mod-1);ans=ans*mpow(i,2*(mod-2)*(tot*2+1)%(mod-1))%mod;
}
printf("%lld\n",ans);
}