1. 程式人生 > >bzoj 2721

bzoj 2721

 題解:首先推一發式子:

原式:\large \tfrac{1}{x}+\tfrac{1}{y}=\tfrac{1}{n!}

通分,移項:

\large n!(x+y)=xy

開啟,合併:

\large n!y=(y-n!)x

再移項,得:

\large x=\tfrac{n!y}{y-n!}

設:

\large t=y-n!

那麼:

\large y=t+n!

代入:

\large x=\tfrac{n!(t+n!)}{t}

化簡:

\large x=n!+\tfrac{(n!)^{2}}{t}

因為x是整數,所以x的數量顯然為能使\large \tfrac{(n!)^{2}}{t}取得整數的t的個數,也就是求\large (n!)^{2}的約數個數

而根據約數個數和公式\large s=\prod_{i=1}^{n}(ci+1)(設一個數\large x=\prod_{i=1}^{n}pi^{ci})

可以將前n個數質因子分解,然後將質因子的冪次相乘,最後將所有冪次*2+1後乘在一起即可。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define mode 1000000007
#define maxn 1000000
using namespace std;
ll fac[1000005];
ll pri[1000005];
bool used[1000005];
int tot=0;
int n;
void init()
{
	scanf("%d",&n);
	for(int i=2;(ll)i*i<=n;i++)
	{
		if(!used[i])
		{
			pri[++tot]=i;
		}
		for(int j=1;j<=tot&&(ll)i*pri[j]<=n;j++)
		{
			used[i*pri[j]]=1;
			if(i%pri[j]==0)
			{
				break;
			}
		}
	}
	for(int i=2;i<=n;i++)
	{
		int t=i;
		for(int j=1;(ll)pri[j]*pri[j]<=t&&j<=tot;j++)
		{
			while(t%pri[j]==0)
			{
				fac[pri[j]]++;
				t/=pri[j];	
				if(fac[pri[j]]>=mode)
				{
					fac[pri[j]]-=mode;
				}
			}
		}
		if(t!=1)
		{
			fac[t]++;
			if(fac[t]>=mode)
			{
				fac[t]-=mode;
			}		
		}
	}  
	ll ans=1;
	for(int i=1;i<=n;i++)
	{
		fac[i]<<=1;
		fac[i]%=mode;
		ans*=(fac[i]+1);
		ans%=mode;
	}
	printf("%lld\n",ans);
}
int main()
{
	init();
	return 0;
}