数论——拓展欧几里德算法复习

news/2024/12/22 19:25:22/

最近也是在备战比赛,所以也是来小小的复习了一下以前学的东西

最重要的是第一道题!

最重要的是第一道题! 

最重要的是第一道题!

先放拓欧板子(不懂怎么推出了就发在评论区或者私聊)

int exgcd(int a,int b,int &x,int &y)
{if(b==0){x=1,y=0;return a;}int x2,y2;int d=exgcd(b,a%b,x2,y2)x=y2;y=x2-a/b*y2;return d;
}

例题:

P2054 [AHOI2005] 洗牌

 我们先来通过6张牌来列举一下

初始        [  1 , 2 , 3 , 4 , 5 , 6  ]

第一次    [  4 , 1 , 5 , 2 , 6 , 3  ]

第二次    [  2 , 4 , 6 , 1 , 3 , 5  ]

第三次   [  1 , 2 , 3 , 4 , 5 , 6  ]

我们通过上面对1这个数据分析,

初始值在1位置,第一次变换后在2位置,第二次变换后在4位置,第三次变换后在1位置

我们发现每次都相当于乘2,但是为什么会被突然折断呢?我们不难想到可能是存在取模操作

因此我们可以大胆猜想这个数是7,也就是(n+1)

我们再对3这个数据进行分析

初始值在3位置,第一次在6位置,第二次再5位置,第三次在3位置

我们发现也是每次位置都乘2,然后取模7(n+1)

因此我们就发现了规律

第i个数m次操作后的位置为 :( i* 2^m)%(n+1)

但是题意问的是m次操作之后,谁在L这个位置,不是问你每个数在哪,而是问你在特定位置的数,很明显,我们一开始想的是遍历一遍所有数,找到谁在那个位置,但是数据是10^10,很明显会超时,因此我们只能去倒推一遍 这个式子

假设x在L那个位置,那么

(2^m)*x= (n+1) *k + L 

请问你看这个式子想到了什么???

我嘞个豆,啥也没想到,你是要毁了我吗?孩子

那我再给你将这个式子变一下形式

(2^m)*x + (n +1) *y =  L  这下能看出来拓展欧几里得的形式了吧

为什么能用拓欧呢?因为题目上说了,n是一个偶数,n+1一定是个奇数,2^m次方一定是个偶数,所以肯定互质的

但是这个式子也很麻烦,能不能再变一下呢?那肯定是可以的

我们先去求 

(2^m)*x + (n +1) *y =  1,然后最后给x乘以L不就是了,说罢,我的气息终于不再掩饰,顷刻将代码炼化出来

77pts

#include <bits/stdc++.h>  
using namespace std;  
#define int long long  int n, m, l;  
int mod;  int fast(int a, int b, int mod) 
{  int result = 1;  int base = a % mod;   while (b > 0) {  if (b % 2 == 1) {  result = (result * base) % mod;  }  base = (base * base) % mod;  b /= 2;  }  return result;  
}  int exgcd(int a, int b, int &x, int &y) 
{  if (b == 0) {  x = 1;   y = 0;  return a;  }  int d = exgcd(b, a % b, x, y);  int x2 = x;  x = y;  y = x2 - (a / b) * y;return d;  
}  signed main() {  ios_base::sync_with_stdio(0);  cin.tie(0);  cout.tie(0);  cin >> n >> m >> l;  mod = n + 1;   int x, y;  int f = fast(2, m, mod);int z = exgcd(f, mod, x, y); x = (x+mod) % mod; cout << (x*l) % mod << '\n'; 
} 

 没想到被暗算了,在运算过程中有可能会导致超出long long的范围,因此需要用到龟速幂,也就是在乘法的过程中用快速乘去运算 

84pts

#include <bits/stdc++.h>  
using namespace std;  
#define int long long  int n, m, l;  
int mod;  int mul(int a,int b)
{int result=0;while(b>0){if(b%2==1){result=(result+a)%mod;}a=(a+a)%mod;b/=2;}return result%mod;
}int fast(int a, int b) 
{  int result = 1;  int base = a % mod;   while (b > 0) {  if (b % 2 == 1) {  result=mul(result,base);}  base = mul(base,base);  b /= 2;  }  return result%mod; 
}  int exgcd(int a, int b, int &x, int &y) 
{  if (b == 0) {  x = 1;   y = 0;  return a;  }  int d = exgcd(b, a % b, x, y);  int x2 = x;  x = y;  y = x2 - (a / b) * y;return d;  
}  signed main() {  ios_base::sync_with_stdio(0);  cin.tie(0);  cout.tie(0);  cin >> n >> m >> l;  mod = n + 1;   int x, y;  int f = fast(2, m);int z = exgcd(f, mod, x, y); x = (x+mod) % mod; cout << (x*l) % mod << '\n'; 
} 

为什么还是错一个点嘞?左思右想都没想明白,

才发现,在逆元前面还是有可能会爆数据,为什么不能用乘法逆元的积性函数的性质,我先去求2和n+1的逆元然后再去m次方后再去乘以L,思考便后,我便不再掩饰自己的气息,仿佛有成尊之势

果然AC了

100pts

#include <bits/stdc++.h>  
using namespace std;  
#define int long long  int n, m, l;  
int mod;  int mul(int a,int b)
{int result=0;while(b>0){if(b%2==1){result=(result+a)%mod;}a=(a+a)%mod;b/=2;}return result%mod;
}int fast(int a, int b) 
{  int result = 1;  int base = a % mod;   while (b > 0) {  if (b % 2 == 1) {  result=mul(result,base);}  base = mul(base,base);  b /= 2;  }  return result%mod; 
}  int exgcd(int a,int b,int &x,int &y)
{if(b==0){x=1,y=0;return a;}int x2,y2;int d=exgcd(b,a%b,x2,y2);x=y2;y=x2-a/b*y2;return d;
}signed main() 
{  ios_base::sync_with_stdio(0);  cin.tie(0);  cout.tie(0);  cin >> n >> m >> l;  mod = n + 1;   int x, y;  exgcd(2, mod, x, y); x = (x+mod) % mod; x=fast(x,m);cout<<mul(x,l) << '\n'; 
} 

P5656 【模板】二元一次不定方程 (exgcd)

思路:题目不是很难,但是处理的条件颇多,只要有耐心并且细心一点都可以写出来

#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int a,b,c;
int gcd(int a,int b)
{return b==0?a:gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y)
{if(b==0){x=1,y=0;return a;}int x2,y2;int d=exgcd(b,a%b,x2,y2);x=y2;y=x2-a/b*y2;return d;
}
signed main()
{cin>>t;while(t--){int x,y;int d;int minnx,minny,maxnx,maxny;int cnt=0;cin>>a>>b>>c;d=gcd(a,b);if(c%d!=0){cout<<-1<<"\n";}else{a/=d,b/=d,c/=d;exgcd(a,b,x,y);x*=c,y*=c;if(x>0&&x%b!=0){minnx=x%b;}else{minnx=x%b+b;}maxny=(c-minnx*a)/b;if(y>0&&y%a!=0){minny=y%a;}else{minny=y%a+a;}maxnx=(c-minny*b)/a; if(maxnx>0){cnt=(maxnx-minnx)/b+1;}if(cnt==0){cout<<minnx<<" "<<minny<<"\n"; }else{cout<<cnt<<" "<<minnx<<" "<<minny<<" "<<maxnx<<" "<<maxny<<"\n";}}}return 0;
}

 P1516 青蛙的约会

思路:这题我们可以写出一个方程

假设第一只青蛙的起始位置为n,速度为a,第二只青蛙的起始位置为m,速度为b 

可以写出方程

(a-b)*t+L *y=m-n

想到了什么?当然是拓欧

直接去写拓欧去求出最小的x,然后x*(m-n)/gcd(a-b,L)即可,当然不要忘记取模L

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,a,b,l;
int gcd(int a,int b)
{return b==0?a:gcd(b,a%b);
}int exgcd(int a,int b,int &x,int &y)
{if(b==0){x=1,y=0;return a;}int x2,y2;int d=exgcd(b,a%b,x2,y2);x=y2;y=x2-a/b*y2;return d;
}signed main()
{int x,y;cin>>n>>m>>a>>b>>l;if(a<b){swap(a,b),swap(n,m);}a=a-b;b=l;int d=gcd(a,b);int c=(m-n+l)%l;exgcd(a,b,x,y);if(c%d!=0){cout<<"Impossible\n";return 0;}l/=d;cout<<(c/d*x%l+l)%l;return 0;
}

P3951 [NOIP2017 提高组] 小凯的疑惑

思路:其实就是看自己的思维的,如果想要能够被表示那么就说明x和y都要大于0,所以不能表示的最小数一定为

-a+?*b(?表示现在还不知道)

那为什么一定为这种形式呢?

x不能等于-2吗?

肯定可以啊,只不过一定不是最大,因为还有一个x=-1的时候更大

那么?的范围是什么,最大是(a-1) 

为什么呢?假如可以为a的话,那么方程就可以化简为a*(b-1),那么就可以用a类型钞票单独表示了

最后就可以写出-a+b*(a-1)

也就是a*b-a-b;

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{int a,b;cin>>a>>b;cout<<(a*b-a-b);return 0;
}

 


http://www.ppmy.cn/news/1520314.html

相关文章

Docker 进阶构建:镜像与仓库管理

目录 三. docker镜像构建 1. docker镜像结构 2. 镜像运行的基本原理 3. 镜像获得方式 4. 镜像构建 5. Dockerfile实例 6. 镜像优化方案 6.1. 镜像优化策略 6.2. 镜像优化示例:缩减镜像层 6.3. 镜像优化示例:多阶段构建 6.4. 镜像优化示例:使用最精简镜像 四. docke…

渗透测试靶机----DC系列 DC-1

渗透测试靶机----DC系列 DC-1 开启靶机&#xff0c;依旧是登陆窗&#xff0c;平平无奇 扫描ip&#xff0c;扫描端口&#xff0c;服务等信息 可以看到这里存在80服务&#xff0c;访问看看 非常明显&#xff0c;这里存在一个Drupal 的cms 并且是一个登录框&#xff0c;思路打开 …

【日常记录-JS】HTML5中使用SVG元素

Author&#xff1a;赵志乾 Date&#xff1a;2024-08-28 Declaration&#xff1a;All Right Reserved&#xff01;&#xff01;&#xff01; 1. 简介 在HTML5中使用SVG元素主要涉及到将SVG代码直接嵌入HTML文档&#xff0c;或者通过HTML元素&#xff08;如<img>、<obj…

协同过滤推荐算法:个性化推荐的基石

在信息爆炸的时代&#xff0c;个性化推荐系统成为帮助用户在海量数据中发现感兴趣的内容的关键工具。协同过滤推荐算法&#xff08;Collaborative Filtering, CF&#xff09;作为推荐系统中最重要的技术之一&#xff0c;它通过分析用户之间的行为模式来提供个性化推荐。本文将深…

大二必做项目贪吃蛇超详解之下篇游戏核心逻辑实现

贪吃蛇系列文章 上篇win32库介绍中篇设计与分析下篇游戏主逻辑 可以在Gitee上获取贪吃蛇代码。 文章目录 贪吃蛇系列文章5. 核心逻辑实现分析5. 3 GameRun5. 3. 1 PrintScore5. 3. 2 CheckVK5. 3. 3 BuyNewNode5. 3. 4 NextIsFood5. 3. 4 EatFood5. 3. 5 NotFood5. 3. 6 Chec…

STM32F401使用float浮点运算崩溃的一个解决实例

今天使用STM32F401开发大彩的串口屏通信&#xff0c;串口使用USART1,DMA通信&#xff0c;系统是FreeRTOS。 使用大彩提供的hmi_driver&#xff0c;执行到SetTextFloat这个函数时崩溃 该函数原型&#xff1a; void SetTextFloat(uint16 screen_id,uint16 control_id,float va…

dinput8.dll错误应该如何修复呢?五种快速修复dinput8.dll错误的问题

dinput8.dll文件是DirectInput库的一部分&#xff0c;主要负责处理游戏控制器的输入&#xff0c;如键盘、鼠标和游戏手柄等。这个文件通常位于Windows系统的System32文件夹中&#xff0c;是许多游戏和应用程序正常运行所必需的组件。它通过提供一个统一的接口来管理不同类型的输…

持续集成与持续部署(CI/CD)的深入探讨

在现代软件开发中&#xff0c;持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;已成为不可或缺的实践。这些方法旨在加快软件交付的速度&#xff0c;同时提高软件的质量和稳定性。通过CI/CD&#xff0c;开发团队可以频繁地将代码更改集成到主分支&…