当前位置: 代码迷 >> 综合 >> bzoj 2721: [Violet 5]樱花
  详细解决方案

bzoj 2721: [Violet 5]樱花

热度:123   发布时间:2023-10-29 04:48:23.0

题意

给你nnn
询问有多少个数对(x,y)(x,y)(x,y)
使得1x+1y=1n!\frac{1}{x}+\frac{1}{y}=\frac{1}{n!}x1?+y1?=n!1?

题解

感觉这题还挺好玩的
提供两个做法吧

一般来说,先同分一下可以得到
xy=n!(x+y)xy=n!(x+y)xy=n!(x+y)
这种式子,一般都是通过提取d=(x,y)d=(x,y)d=(x,y)来化简
这题也可以这么做,那么可以变成
dx′y′=n!(x′+y′)dx'y'=n!(x'+y')dxy=n!(x+y)
可以发现(x′+y′,x′)=1,(x′+y′,y′)=1(x'+y',x')=1,(x'+y',y')=1(x+y,x)=1,(x+y,y)=1
那么可以得到
(x′+y′)∣d(x'+y')|d(x+y)d
d=k(x′+y′)d=k(x'+y')d=k(x+y)
代进去就是kx′y′=nkx'y'=nkxy=n
可以发现,等价于求互质对数(x′,y′)(x',y')(x,y)的数量
把n分解质因数之后就可以DP来做了
可以化为一般的式子

还有一个很神奇的做法
可以发现,x>n!,y>n!x>n!,y>n!x>n!,y>n!
那么就直接设y=n!+dy=n!+dy=n!+d
丢进去就是
x(n!+d)=n!(x+n!+d)x(n!+d)=n!(x+n!+d)x(n!+d)=n!(x+n!+d)
把括号打开,可以发现,每一个d对应一个x,y
然后就变成求(n!)2(n!)^2(n!)2的因子数了23333
怎么感觉这么神奇啊

然后直接算因子数就好了
虽然这个数很大,但是质因数还是10510^5105级别,暴力算就行了

CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1000005;
const int MOD=1e9+7;
int add (int x,int y)   {
    x=x+y;return x>=MOD?x-MOD:x;}
int mul (int x,int y)   {
    return (LL)x*y%MOD;}
int dec (int x,int y)   {
    x=x-y;return x<0?x+MOD:x;}
int Pow (int x,int y)
{
    if (y==1) return x;int lalal=Pow(x,y>>1);lalal=mul(lalal,lalal);if (y&1) lalal=mul(lalal,x);return lalal;
}
int n;
bool vis[N];
int pri[N],tot;
void Init ()
{
    memset(vis,false,sizeof(vis));for (int u=2;u<=n;u++){
    if (vis[u]==false)	pri[++tot]=u;for (int i=1;i<=tot;i++){
    int j=pri[i];if (n/u<j) break;vis[j*u]=true;if (u%j==0) break;}}
}
int main()
{
    scanf("%d",&n);Init();int ans=1;for (int u=1;u<=tot;u++){
    int x=pri[u];int lalal=0;for (int i=1;i<=n/x;i*=x)	lalal=lalal+n/(i*x);lalal=add(lalal,lalal);lalal=add(lalal,1);ans=mul(ans,lalal);}printf("%d\n",ans);return 0;
}