类欧几里得算法

类欧几里得算法

类欧几里得算法之所以被称为类欧几里得是因为其算法复杂度证明与扩展欧几里得算法类似。

我认为类欧更偏向于是一种思想。

其主要思想就是寻找可以简便计算的边界,然后通过化式子将不同情况化为边界递归计算。

P5170 【模板】类欧几里得算法

推导

f(a,b,c,n)=i=0nai+bc

g(a,b,c,N)=i=0Nai+bc2

h(a,b,c,N)=i=0Niai+bc

f(a,b,c,N)={(N+1)bca=0N(N+1)2ac+(N+1)bc+f(amodc,bmodc,c,N)ac or bcNMf(c,cb1,a,M1),M=aN+bcotherwise

g(a,b,c,N)={(N+1)bc2a=0g(amodc,bmodc,c,N)+2ach(amodc,bmodc,c,N)+2bcf(amodc,bmodc,c,N)+N(N+1)(2N+1)6ac2+N(N+1)acbc+(N+1)bc2ac or bcNM(M+1)f(a,b,c,N)2h(c,cb1,a,M1)2f(c,cb1,a,M1)otherwise

h(a,b,c,N)={N(N+1)2bca=0h(amodc,bmodc,c,N)+N(N+1)(2N+1)6ac+N(N+1)2bcac or bc12[MN(N+1)g(c,cb1,a,M1)f(c,cb1,a,M1)]otherwise

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
#include<tuple>
using namespace std;
inline int read(){
	int w=0,x=0;char c=getchar();
	while(!isdigit(c))w|=c=='-',c=getchar();
	while(isdigit(c))x=x*10+(c^48),c=getchar();
	return w?-x:x;
}
const int mod=998244353;
tuple<int,int,int> calc(long long a,long long b,long long c,long long n){
	int f,g,h,fn,gn,hn;
	if(!a){
		fn=(n+1)*(b/c)%mod;
		gn=(n+1)*(b/c)%mod*(b/c)%mod;
		hn=n*(n+1)%mod*((mod+1)>>1)%mod*(b/c)%mod;
	}else if(a>=c or b>=c){
		tie(f,g,h)=calc(a%c,b%c,c,n);
		fn=(n*(n+1)%mod*((mod+1)>>1)%mod*(a/c)%mod+(n+1)*(b/c)%mod+f)%mod;
		gn=(n*(n+1)%mod*(2*n+1)%mod*((mod+1)/6)%mod*(a/c)%mod*(a/c)%mod+(n+1)*(b/c)%mod*(b/c)%mod+n*(n+1)%mod*(a/c)%mod*(b/c)%mod+2*(b/c)%mod*f%mod+g+2*(a/c)%mod*h%mod)%mod;
		hn=(n*(n+1)%mod*(2*n+1)%mod*((mod+1)/6)%mod*(a/c)%mod+n*(n+1)%mod*((mod+1)>>1)%mod*(b/c)%mod+h)%mod;
	}else{
		tie(f,g,h)=calc(c,c-b-1,a,(a*n+b)/c-1);
		fn=(n*((a*n+b)/c)%mod-f+mod)%mod;
		gn=(n*((a*n+b)/c)%mod*((a*n+b)/c+1)%mod-fn+mod-2*f%mod+mod-2*h%mod+mod)%mod;
		hn=(n*(n+1)%mod*((a*n+b)/c)%mod*((mod+1)>>1)%mod-f*((mod+1ll)>>1)%mod+mod-g*((mod+1ll)>>1)%mod+mod)%mod;
	}
	return tie(fn,gn,hn);
}
signed main(){
	int T=read(),n,a,b,c,f,g,h;
	while(T--) n=read(),a=read(),b=read(),c=read(),tie(f,g,h)=calc(a,b,c,n),printf("%d %d %d\n",f,g,h);
	return 0;
}

P5171 Earthquake

题意

求满足 ax+byc 的非负整数解的个数。

推导

ycaxbans=x=0cacaxb+1=x=0cac+(ba)xbx+1(x=0cac+(ba)xb)ca(ca+1)2+ca+1

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
#define int long long
using namespace std;
inline int read(){
	int w=0,x=0;char c=getchar();
	while(!isdigit(c))w|=c=='-',c=getchar();
	while(isdigit(c))x=x*10+(c^48),c=getchar();
	return w?-x:x;
}
long long f(long long a,long long b,long long c,long long n){
	if(!a) return (n+1)*(b/c);
	if(a>=c or b>=c) return n*(n+1)/2*(a/c)+(n+1)*(b/c)+f(a%c,b%c,c,n);
	return n*((a*n+b)/c)-f(c,c-b-1,a,(a*n+b)/c-1);
}
signed main(){
	int a=read(),b=read(),c=read();
	if(a>b)swap(a,b);
	printf("%lld\n",f(b-a,c,b,c/a)-1ll*(c/a)*(c/a+1)/2+c/a+1);
}

P5172 Sum

推导

ans=d=1n(1)dr=d=1n12(drmod2)=d=1n12(dr2dr2)

f(a,b,c,n)=d=1nar+bcd

ar+bc1 时,

f(a,b,c,n)=d=1nar+bcd=d=1nar+bcar+bccd+ar+bcd=d=1nf(a,bcar+bc,c,n)+12n(n+1)ar+bc

ar+bc=0 时,

f(a,b,c,n)=d=1nar+bcd=d=1np=1ar+bcn[par+bcd]=d=1np=1ar+bcn[dcpar+b]=p=1ar+bcnncpar+b(无理数,大于等于与大于等价)=ar+bcnnp=1ar+bcnc(arb)a2rb2p=ar+bcnnf(ac,bc,a2rb2,ar+bcn)

ans=12f(1,0,1,n)+4f(1,0,2,n)

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
	int w=0,x=0;char c=getchar();
	while(!isdigit(c))w|=c=='-',c=getchar();
	while(isdigit(c))x=x*10+(c^48),c=getchar();
	return w?-x:x;
}
double sr;
int r;
long long gcd(long long a,long long b){return b?gcd(b,a%b):a;}
long long f(long long a,long long b,long long c,long long n){
	if(!n) return 0;
	long long g=gcd(gcd(a,b),c);a/=g,b/=g,c/=g;
	long long k=(a*sr+b)/c;
	if(k) return f(a,b-c*k,c,n)+n*(n+1)/2*k;
	return (long long)((a*sr+b)/c*n)*n-f(a*c,-b*c,a*a*r-b*b,(long long)((a*sr+b)/c*n));
}
signed main(){
	int T=read(),n;
	while(T--){
		n=read(),r=read();sr=sqrt(r);
		if((int)sr*(int)sr==r) printf("%d\n",((int)sr&1)?-(n&1):n);
		else printf("%lld\n",n-2*f(1,0,1,n)+4*f(1,0,2,n));
	}
	return 0;
}

P5179 Fraction

推导

f(a,b,p,q,c,d){q=1,p=ac+1ac+1cd1p=1,q=dc+1a=0f(b,a,q,p,d,c)abcdf(amodb,b,p,q,cabd,d),p=p+abqab

代码

#include<cstdio>
using namespace std;
void calc(long long a,long long b,long long &p,long long &q,long long c,long long d){
	if(a/b+1<=(c+d-1)/d-1) p=a/b+1,q=1;
	else if(!a) p=1,q=d/c+1;
	else if(a<=b and c<=d) calc(d,c,q,p,b,a);
	else calc(a%b,b,p,q,c-a/b*d,d),p+=a/b*q;
}
signed main(){
	long long a,b,c,d,p,q;
	while(~scanf("%lld%lld%lld%lld",&a,&b,&c,&d)) calc(a,b,p,q,c,d),printf("%lld/%lld\n",p,q);
	return 0;
}
posted @   Star_Cried  阅读(780)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示