2024年之完全平方数、樱花--三个简单数论题
P00364. 完全平方数之差
Description
给你一个正整数N,问其是否可分解成两个正的完全平方数之差
例如 N=8时
8=3 * 3- 1 * 1
Format
Input
一行给出数字N
N<=1e18
Output
见样例
Samples
输入数据 1
8
输出数据 1
yes
输入数据 2
1
输出数据 2
no
Hint
1只能写在1^2-0^2
但0不是正数
Description
给你一个数字N,希望在[1..N]之间找出数字x,y,满足下列条件
1<=x,y<=N,并且x * x-y是个完全平方数,0也算是完全平方数
问能找出多少对(x,y)来,输出结果%998244353
Format
Input
第一行给出N
N<=1e12
Output
如题,输出结果%998244353.
Samples
输入数据 1
3
输出数据 1
2
输入数据 2
10
输出数据 2
8
输入数据 3
10000000000
输出数据 3
52583544
Hint
对于样例来说
xx=1,yy=1
xx=2,yy=3
求x^2-y=z^2
这个式子不好变形,所以换一下,变成
x^2-z^2=y
于是(x+z)(x-z)=y
简化一下
令p=x+z,q=x-z,于是x=(p+q)/2,z=(p-q)/2,y=pq
于是p*q=y,因为1<=y<=N
于是p*q<=N
易知
p>=q
于是q<=sqrt(n).于是枚举q,然后p=n/q,注意此时的p是有这么多选择的,其值不唯一
由x=(p+q)/2,可知p,q必须是同奇同偶,只有这样才能得到x
于是问题转化成
对于一个数列,以q开头,公差为2,最后一个数字的值不超过p.现需统计这个数列共有多少项
于是q+(项数-1)*2<=p
于是项数<=(p-q)/2+1
总结:这类题都是通过数学变换,找到某个数字的范围,然后进行枚举
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
int main()
{
long long n;
cin>>n;
long long sum=0;
//x*x-y*y=z...(x+y)(x-y)=z
//p为x+y,q为x-y.
//p*q<=n,p>=q
//p,q同奇同偶
for(long long i=1;i*i<=n;i++)
{
long long j=n/i;
long long s=(j-i)/2+1;
sum=(sum+s)%mod;
}
cout<<sum%mod<<endl;
return 0;
}
樱花
Description
给定数字N,有多少正整数对(x,y)满足1/x+1/y=1/N!
Format
Input
一个正整数N,N<=1000000
Output
一个整数并对10^9+7取模
Samples
输入数据 1
2
输出数据 1
3
hint //有三个整数对(3,6),(4,4),(6,3)满足题意
给定数字N,有多少正整数对(x,y)满足1/x+1/y=1/N!
输入格式
一个正整数N,N<=1000000
输出格式
一个整数,如上所述,对10^9+7取模
样例输入
2
样例输出
3
//有三个整数对(3,6),(4,4),(6,3)满足题意
题解:
先令n! = a:
1 / x + 1 / y = 1 / a => x = y * a / (y - a)
再令 k = y - a:
于是x = a + a ^ 2 / k => k | a ^ 2
我们来看下样例是如何求出来的,当N=2时,a=2
故当K=1时,x=2+4/1=6,y=k+a=1+2=3
故当K=2时,x=2+4/2=4,,y=k+a=2+2=4
故当K=4时,x=2+4/4=3,,y=k+a=4+2=6
因而此题只需要对N!^2,进行约数分解就好了。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 1000100
#define MOD 1000000007
int n,ans=1;
bool zs[MAX];
int main()
{
cin>>n;
for(int i=2;i<=n;++i)
if(!zs[i])
{
for(int j=i;j<=n/i;j++)
zs[j*i]=true;
int p=n,s=0;
while(p)
s=(s+p/i*2)%MOD,p/=i;
ans=1ll*ans*(s+1)%MOD;
}
cout<<ans<<endl;
return 0;
}
另一个较为少见的写法
#include <cstdio>
#define maxn 1000010
#define mod 1000000007
using namespace std;
long long v[maxn], pri[maxn], cnt[maxn], d;
inline void primes(long long n)
{
for(long long i = 2; i <= n; i++)
{
if(!v[i])
v[i] = i, pri[++d] = i;
for(long long j = 1; j <= d; j++)
{
if(pri[j] * i > n || pri[j] > v[i])
break;
v[pri[j] * i] = pri[j];
}
}
}
inline void eular(long long n)
{
while(n > 1)
cnt[v[n]]++, n /= v[n];
}
int main() {
primes(1000000);
long long n;
scanf("%lld", &n);
for(long long i = 1; i <= n; i++)
eular(i);
long long ans = 1;
for(long long i = 1; i <= d; i++)
if(cnt[pri[i]])
{
ans = ans * (cnt[pri[i]] * 2 % mod + 1) % mod;
}
printf("%lld\n", ans);
return 0;
}