2020.03.14日常总结

洛谷P1593      因子和 \color{green}{\text{洛谷P1593\ \ \ \ \ 因子和}} 洛谷P1593      因子和

【 题 意 】 : \color{blue}{【题意】:} 给定 a , b a,b a,b,求 a b a^b ab 的所有因子的和对 9901 9901 9901 取模的值,即求:

∑ i = 1 a b i ( i ∣ a b ) m o d    9901 \sum\limits_{i=1}^{a^b} i(i|a^b)\mod 9901 i=1abi(iab)mod9901

1 ≤ a , b ≤ 5 × 1 0 7 1 \leq a,b \leq 5 \times 10^7 1a,b5×107

【 思 路 】 : \color{blue}{【思路】:} a = ∏ i = 1 m p i k i a= \prod\limits_{i=1}^{m} p_i^{k_i} a=i=1mpiki,其中 p i p_i pi 是质数, k i ≥ 0 ( 1 ≤ i ≤ m ) k_i\geq 0(1 \leq i \leq m) ki0(1im)

那么, a b = ∏ i = 1 m p i k i × b a^b=\prod\limits_{i=1}^{m} p_i^{k_i \times b} ab=i=1mpiki×b。由定理,答案 ans = ∏ i = 1 m ( ∑ j = 0 k i × b p i j ) \text{ans}=\prod\limits_{i=1}^{m} (\sum\limits_{j=0}^{k_i \times b}p_i^j) ans=i=1m(j=0ki×bpij)

直接算铁定不行,但是由费马小定理得, a t − 1 ≡ 1 ( m o d t )   ( t a^{t-1} \equiv 1 \pmod t\ (t at11(modt) (t是质数 ) ) ) 。由题意, p = 9901 p=9901 p=9901,于是我们可以算出 res= ∑ j = 0 p − 2 p i j \text{res=}\sum\limits_{j=0}^{p-2} p_i^j res=j=0p2pij。然后,因为后面的项一定与前面的某一项相等,于是我们可以令这个数列 t − 2 t-2 t2 位为一个循环,于是我们可以直接由 res \text{res} res 得到所有循环的总和。对于后面剩余的项,我们可以暴力得到。

举个例子,比如 k i × b = 2 × t k_i \times b = 2 \times t ki×b=2×t,我们可以求出 res= ∑ j = 0 p − 2 p i j \text{res=}\sum\limits_{j=0}^{p-2} p_i^j res=j=0p2pij,然后答案 ans = res × 2 + ∑ j=0 3 p i j \text{ans = res} \times 2 + \sum\limits_{\text{j=0}}^{3} \text{p}_{\text{i}}^j ans = res×2+j=03pij

时间复杂度没用等比数列优,但是需要的知识点少,比较好理解(至少个人认为如此)。

【 代 码 】 : \color{blue}{【代码】:}

const int mod=9901;
int calc(int x,long long t){
	int ret=1,ans=0;
	if (x==mod) return 1;
	else if (t<mod){
		for(int i=0;i<=t;i++){
			ans=(ans+ret)%mod;
			ret=(1ll*ret*x)%mod;
		}
	}
	else{
		for(int i=0;i<=mod-2;i++){
			ans=(ans+ret)%mod;
			ret=(1ll*ret*x)%mod;
		}
		ans=(1ll*ans*((t+1)/(mod-1)))%mod;
		for(int i=1;i<=(t+1)%(mod-1);i++){
			ans=(ans+ret)%mod;
			ret=(1ll*ret*x)%mod;
		}
	}
	return ans;
}
int ans=1,a,b,n;
int main(){
	scanf("%d%d",&a,&b);n=a;
	for(int i=2;1ll*i*i<=n;i++)
		if (n%i==0){
			register int ret=0;
			while (n%i==0){
				n/=i;ret++;
			}
			ans=(1ll*ans*calc(i,1ll*ret*b))%mod;
		}
	if (n>1) ans=(1ll*ans*calc(n,b))%mod;
	printf("%d",(ans+mod)%mod);
	return 0;
}

你可能感兴趣的:(数学(数论),循环数列优化,费马小定理)