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;
}

  

posted @ 2022-09-22 10:47  我微笑不代表我快乐  阅读(82)  评论(0编辑  收藏  举报