【一句話題意】有t個詢問,求
t<=1e6,n<=1e7 時限比1s長一點。
【分析】
原題不如概括後簡潔和清晰,但概括和抽象也是圖論和數論所要強調的能力。這次考試犯了數論題的大忌:死盯着題目想結論,而不是概括出式子進行觀察和思考。
明顯的離線算法,所以問題在於預處理的複雜度上,只能比線性多一點。
將式子展開可以得到
對於分子可以O(n)預處理,關鍵在於gcd(i,j)的計算。首先考慮的是利用已有結果推得未知結果。
如果我已經知道了f(n-1)。顯然gcd(i,n)一定是n的約數,考慮到n的約數個數是log級的,所以我們枚舉gcd的大小。當gcd大小爲x時,顯然有,所以gcd爲x對答案貢獻就是x乘上與互質的數的個數。用公式書寫就是。考慮到可以O(n)預處理,所以複雜度就是O(nlogn)。
還是過不了,怎麼辦?我們單獨考慮每個素數對答案的貢獻,對於一個素數x,它在k*x處會對答案有x(2k-1)的貢獻,求一遍前綴積即爲答案。
【code】
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int mod=19260817;
const int maxn=1e7+1000;
const int T=1e7;
int sum[maxn],mul[maxn];
bool flag[maxn];
int n,t;
int pw(int x,int p){
int ret=1;
while(p>0){
if(p&1) ret=1ll*ret*x%mod;
x=1ll*x*x%mod,p>>=1;
}
return ret;
}
void pre(){
flag[1]=true;
for(int i=0;i<=T;i++) sum[i]=1;
for(int i=2;i<=T;i++)
if(flag[i]==false){
long long t=i;
for(;t<=T;t*=i){//p^k
for(int tmp=t,num=i;tmp<=T;tmp+=t,num=1ll*num*i%mod*i%mod)//num的奇形怪狀處理是爲了避免p^k被,p,p^2……處理多次
sum[tmp]=1ll*sum[tmp]*num%mod;
}
for(int k=i;k<=T;k+=i) flag[k]=true;
}
for(int i=1;i<=T;i++) sum[i]=1ll*sum[i-1]*sum[i]%mod;
for(int i=1;i<=T;i++) sum[i]=1ll*sum[i]*sum[i]%mod;
mul[0]=1;for(int i=1;i<=T;i++) mul[i]=1ll*mul[i-1]*i%mod;
}
inline void read(int &x){
x=0;char tmp=getchar();
while(tmp<'0'||tmp>'9') tmp=getchar();
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
int main(){
pre();
cin>>t;
while(t--){
read(n);
printf("%lld\n",1ll*pw(mul[n],2*n)*pw(sum[n],mod-2)%mod);
}
return 0;
}