洛谷 P1445 [Violet]樱花

题目链接

首先数学推导

\[\frac{1}{x} + \frac{1}{y} = \frac{1}{n!} \\\frac{x+y}{xy} = \frac{1}{n!}\\(x+y)n! = xy \\xy-(x+y)n! = 0 \\xy - (x+y)n! + (n!)^2 = (n!)^2 \\(x-n!)(y-n!) = (n!)^2 \\ \]

于是乎我们只需要求 \((n!)^2\) 的约数个数即可

再由于约数定理,\(ans = \prod_{i=1}^{k}(s_i+1)\) ( 1~n 之间有k个质数)

得到答案为\(\prod_{i=1}^{k}(s_i+s_i+1)\)

统计答案时可以先用欧拉筛获得所有质数,并且获得每个合数的一个质因数,记录在\(pre\)

然后从后往前扫,每获得一个质数就统计答案,每获得一个合数就拆分,把答案加到两个数里去,分别是\(pre[i]\)\(i/pre[i]\)

这样就\(O(n)\)出答案

[Code]


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

int read(){
	int x=0,flag=1; char c;
	for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
	for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
	return x*flag;
}

const int mod=1e9+7;
const int N=1e6+10;

int n;
bool p[N];
int prime[N],cnt;
int pre[N],a[N];

void euler(){
    p[0]=p[1]=1;
    pre[0]=pre[1]=-1;
    for(int i=2;i<=n;i++){
	    if(!p[i]){
		    prime[++cnt]=i;
		    pre[i]=i;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
			
			p[prime[j]*i]=1;
		    pre[prime[j]*i]=prime[j];
		    
		    if(i%prime[j]==0) break; 
		}
	}
}


int main() {
    n=read();
    euler();
    long long ans=1;
    for(int i=n;i>=2;i--){
	    a[i]++;
	    if(!p[i]) { ans=ans*(a[i]+a[i]+1)%mod; continue; }
	    a[pre[i]]+=a[i]; a[i/pre[i]]+=a[i];
	    a[i]=0;
	}
	
	printf("%lld\n",ans);
	return 0;
}


posted @ 2020-01-20 09:48  zhuzihan  阅读(110)  评论(0编辑  收藏  举报