1. 程式人生 > >洛谷3704 [SDOI2017] 數字表格 【莫比烏斯反演】

洛谷3704 [SDOI2017] 數字表格 【莫比烏斯反演】

ont nbsp 產生 ID IV mod return esp SQ

題目分析:

比較有意思,但是套路的數學題。

題目要求$ \prod_{i=1}^{n} \prod_{j=1}^{m}Fib(gcd(i,j)) $.

註意到$ gcd(i,j) $有大量重復,采用莫比烏斯反演。可以寫成:

$ \prod_{i=1}^{min(n,m)}Fib(i)^{\sum_{i|d}\mu(\frac{d}{i})\lfloor \frac{n}{d}\rfloor\lfloor \frac{m}{d}\rfloor} $.

更進一步的,我們可以發現冪是一個求和,那麽把求和依次提出,再重新組合在一起,就變成了:

$ \prod_{i=1}^{min(n,m)}(\prod_{i|d}Fib(i)^{\mu(\frac{d}{i})})^{\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor} $.

可以發現最外層的積的下標是$ i $或$ d $對答案沒有影響,原因我們可以考慮當下標是$ i $的時候,它會對它的每個倍數產生影響,而倍數的影響是不論$ i $的。所以對於每個倍數我們同樣可以枚舉因數,式子可以寫成:

$ \prod_{d=1}^{min(n,m)}(\prod_{i|d}Fib(i)^{\mu(\frac{d}{i})})^{\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor} $.

註意這個式子,它的裏層是一個只與當前的$ d $有關的式子,而外層是一個典型的分塊。那麽我們預處理出裏面的情況並做前綴積,外面再采用分塊,這道題就可以順利解決。

對於裏面的式子,我們需要$ O(nlog{n}) $進行預處理,而每個詢問我們可以分塊解決,單次詢問的時間復雜度是$ O(\sqrt{n}log{n}) $所以時間復雜度是$O(nlog{n}+T\sqrt{n}log{n})$.

註意到這題沒有用到斐波那契數列的任何性質,所以函數$ Fib(x) $可以改成任意其它函數。

代碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int mod = 1000000007;
 5 const int maxn = 1000005;
 6 
 7 const int N = 1000000
; 8 9 int n,m; 10 int Fib[maxn],Inv[maxn]; 11 int MFib[maxn],MInv[maxn]; 12 13 int flag[maxn],prime[maxn>>3],mu[maxn],num; 14 15 int fast_pow(int now,long long pw){ 16 int z = now,ans = 1;long long im = 1; 17 while(im <= pw){ 18 if(im & pw) ans = (1ll*ans*z)%mod; 19 z = (1ll*z*z)%mod; im <<= 1; 20 } 21 return ans; 22 } 23 24 void GetMiu(){ 25 flag[1] = 1;mu[1] = 1; 26 for(int i=2;i<=N;i++){ 27 if(!flag[i]) prime[++num] = i,mu[i] = -1; 28 for(int j=1;j<=num&&i*prime[j]<=N;j++){ 29 flag[i*prime[j]] = 1; 30 if(i % prime[j] == 0) {mu[i*prime[j]] = 0;break;} 31 else mu[i*prime[j]] = -mu[i]; 32 } 33 } 34 } 35 36 void init(){ 37 GetMiu(); 38 Fib[0] = 0; Fib[1] = 1; 39 for(int i=2;i<=N;i++) Fib[i] = (Fib[i-1]+Fib[i-2])%mod; 40 for(int i=0;i<=N;i++) Inv[i] = fast_pow(Fib[i],mod-2); 41 for(int i=0;i<=N;i++) MFib[i] = 1; 42 for(int i=1;i<=N;i++){ 43 for(int j=1;i*j<=N;j++){ 44 if(mu[j] == 0) continue; 45 if(mu[j] == 1) MFib[i*j] = (1ll*MFib[i*j]*Fib[i])%mod; 46 else MFib[i*j] = (1ll*MFib[i*j]*Inv[i])%mod; 47 } 48 } 49 for(int i=1;i<=N;i++) MFib[i] = (1ll*MFib[i]*MFib[i-1])%mod; 50 for(int i=0;i<=N;i++) MInv[i] = fast_pow(MFib[i],mod-2); 51 } 52 53 void work(){ 54 int res = 1; 55 for(int i=1;i<=min(n,m);){ 56 int nxt = min(n/(n/i),m/(m/i)); 57 long long z1 = 1ll*(n/i)*(m/i); 58 res = (1ll*res*fast_pow((1ll*MFib[nxt]*MInv[i-1])%mod,z1))%mod; 59 i = nxt+1; 60 } 61 printf("%d\n",res); 62 } 63 64 int main(){ 65 init(); 66 int T; scanf("%d",&T); 67 while(T--){ 68 scanf("%d%d",&n,&m); 69 work(); 70 } 71 return 0; 72 }

洛谷3704 [SDOI2017] 數字表格 【莫比烏斯反演】