P2155 [SDOI2008]沙拉公主的困惑


題面

題目可簡化為求:

\[\displaystyle\sum_{i=1}^{n!}{[gcd(i,m!)=1]}(1到n!中,所有與m!互質的數的個數) \]

如何求解:

首先假設有\(gcd(a,b) = 1\),則一定有\(gcd(a+b,b)=1\)

所以考慮把\(n!\)分為\(\frac{n!}{m!}\)塊,其中\(m \leq n\),所以\(n!\) mod \(m!\) 一定等於\(0\),即我們分出的一定是整數塊。

而且其中每一塊中與\(m!\)互質的數的個數一定是相等的。

此時我們的式子為:

\[\frac{n!}{m!}\times\displaystyle\sum_{i=1}^{m!}[gcd(i,m!)=1] \]

其中

\[\displaystyle\sum_{i=1}^{m!}[gcd(i,m!)=1] \]

等等,是不是看着有點眼熟?小於等於\(m!\)的正整數中與\(m!\)互質的數的數目...不就是歐拉函數的定義嗎?

那這不就是\(\varphi(m!)\)嗎?

於是我們的式子就可以完美的變為:

\[\frac{n!}{m!}\times\varphi(m!) \]

因為求\(\varphi(i)\)的公式為:

\[\varphi(i)=i\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x}(p為i的所有質因數) \]

\(\varphi(i)\)換為\(\varphi(m!)\)代進\(\frac{n!}{m!}\times\varphi(m!)\)去展開:

\[\frac{n!}{m!}\times\varphi(m!)=\frac{n!}{m!}\times m!\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x} \]

於是我們的式子就可以化簡為:

\[n!\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x} \]

注意此時\(p\)\(m!\)的所有質因數。

那么我們的問題就轉化為求:

\[n!\times\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x} \]

\(n!\)好求,對於\(\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x}\)我們線性求出逆元即容易求出。

線性預處理出來\(1\)\(maxn\)的所有\(i!\)\(\frac{p_1-1}{p_1}\times...\times\frac{p_x-1}{p_x}\)即可\(O(1)\)的詢問。

時間復雜度為\(O(1e7+t)\)

由蒟蒻代碼自帶大常數+某谷評測機不穩定,有時候能過有時候不能過,開了\(O_2\)穩過。

代碼:

#include <bits/stdc++.h>
using namespace std;

template<typename temp>
void read(temp &x){
	x = 0;temp f = 1;char ch;
	while(!isdigit(ch = getchar())) (ch == '-') and (f = -1);
	for(x = ch^48; isdigit(ch = getchar()); x = (x<<1)+(x<<3)+(ch^48));
	return (void)(x *= f);
}
template <typename temp, typename ...Args>
void read(temp& a, Args& ...args){read(a), read(args...);}

const int maxn = 1e7+10;

int t, mod, n, m, cnt, prime[maxn];
long long inv[maxn], fac[maxn], fi[maxn];
bool is_prime[maxn];

void memset_mine(){ 
	fac[0] = fac[1] = inv[0] = inv[1] = fi[0] = fi[1] = 1;
	for(int i = 2; i <= maxn; i ++){
		fac[i] = (fac[i-1]*i)%mod, inv[i] = mod-mod/i*inv[mod%i]%mod;
		fi[i] = fi[i-1];
		if(!is_prime[i]) prime[++cnt] = i, fi[i] = (fi[i]%mod*(i-1)%mod*inv[i]%mod)%mod;
		for(int j = 1; j <= cnt and i*prime[j] <= maxn; j ++){
			is_prime[i*prime[j]] = 1;
			if(!(i%prime[j])) break;
		}
	}
}

signed main(){
	read(t, mod);
	memset_mine();
	while(t --){
		read(n, m);
		printf("%lld\n", fac[n]%mod*fi[m]%mod);
	}
	return 0;
}

沒啦qwq。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM