P1082 [NOIP2012 提高组] 同余方程

该博客介绍了如何使用拓展欧几里得算法解决模线性同余方程ax≡1 (mod b)的最小正整数解。题目要求在给定的a和b条件下找到最小的x,保证输入数据一定有解。解题思路包括应用拓展欧几里得算法,并通过特定方式调整解以找到最小正整数解。代码示例展示了C++实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


原题链接

P1082
题目类型: 普 及 + / 提 高 {\color{lightgreen} 普及+/提高} +/
AC记录:Accepted

题目大意

求关于 x x x的同余方程 a x ≡ 1 (   m o d     b ) ax\equiv 1(\bmod\ b) ax1(mod b)的最小正整数解。

输入格式

一行,包含两个正整数 a , b a,b a,b,用一个空格隔开。

输出格式

一个正整数 x 0 x_0 x0,即最小正整数解。输入数据保证一定有解。

S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input

3 10

S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output

7

H i n t & E x p l a i n \mathbf{Hint\&Explain} Hint&Explain

数据范围

对于 40 % 40\% 40%的数据, 2 ≤ b ≤ 1 , 000 2≤b≤1,000 2b1,000
对于 60 % 60\% 60%的数据, 2 ≤ b ≤ 50 , 000 , 000 2≤b≤50,000,000 2b50,000,000
对于 100 % 100\% 100%的数据, 2 ≤ a , b ≤ 2 , 000 , 000 , 000 2\le a,b\le 2,000,000,000 2a,b2,000,000,000

解题思路

这题可以用拓展欧几里得算法(下面简称拓欧)来解决。

如果不会欧几里得算法或拓展欧几里得算法的童鞋,可以戳我

而拓欧解的方程是这样的: a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b),与我们的题目有很大的区别。所以我们要把题目中的同余方程变成这个样子: a x + b y = 1 ax+by=1 ax+by=1。其中的 y y y为辅助解,没什么用。又由于题目中说了:输入数据保证一定有解,所以又可以得知: gcd ⁡ ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1


解完方程以后,还有一个需要注意的点,就是题目要求的是最小正整数解,那么我们解出一个解后,如何找出其他的解呢?
答案是:设方程的一个解为 x x x,则 x + k b x+kb x+kb都是方程的解。
如果把 x + k b x+kb x+kb代入原方程,可以得到 a ( x + k b ) ≡ 1 (   m o d     b ) a(x+kb)\equiv 1(\bmod\ b) a(x+kb)1(mod b),去括号后变成 a x + k a b ≡ 1 (   m o d     b ) ax+kab\equiv 1(\bmod\ b) ax+kab1(mod b)。由于 k a b kab kab一定是 b b b的倍数,所以方程又变成了 a x ≡ 1 (   m o d     b ) ax\equiv 1(\bmod\ b) ax1(mod b),即为原方程。所以求最小正整数解就相当于把 x x x变成 ( ( x +   m o d     b ) + b )   m o d     b ((x+\bmod\ b)+b)\bmod\ b ((x+mod b)+b)mod b
注意:由于解出来的 x x x有可能是负数,所以上式在   m o d     b \bmod\ b mod b之后还要再加上一个 b b b再取模。


最后,祝大家早日
请添加图片描述

上代码

#include<iostream>

using namespace std;

int              x,y;

int exgcd(int a,int b)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    int temp=exgcd(b,a%b);
    int tx=x;
    x=y;
    y=tx-a/b*y;
    return temp;
}

int main()
{
    int a,b;
    cin>>a>>b;
    exgcd(a,b);
    // cout<<x<<" "<<y<<endl;
    x=((x%b)+b)%b;
    cout<<x<<endl;
    return 0;
}

完美切题 ∼ \sim

### NOIP 2000 提高 方格取数问题分析 该问题属于经典的动态规划类题目,目标是在给定的一个二维矩阵中选取若干个不相邻的数字使得总和最大。此问题可以通过状态转移的方式解决。 #### 动态规划的核心思路 定义 `dp[i][j]` 表示到达第 `i` 行第 `j` 列时能够取得的最大数值之和[^1]。由于每次移动仅能向右或者向下,因此可以得出如下状态转移方程: 对于任意位置 `(i, j)` 的状态更新方式为: \[ dp[i][j] = \text{matrix}[i][j] + \max(dp[i-1][j], dp[i][j-1]) \] 其中需要注意边界条件处理以及初始值设定。当处于第一行或第一列时,路径的选择会受到限制[^2]。 #### 边界情况考虑 如果当前单元位于网格的第一行,则只能由左侧进入;同理,若当前位置处在首列,则唯一可能来自上方。这些特殊情况需单独初始化以确保计算准确性[^3]。 ```python def max_sum(matrix): m, n = len(matrix), len(matrix[0]) # 初始化 DP 数 dp = [[0]*n for _ in range(m)] # 设置起点 dp[0][0] = matrix[0][0] # 填充第一行 for j in range(1, n): dp[0][j] = dp[0][j-1] + matrix[0][j] # 填充第一列 for i in range(1, m): dp[i][0] = dp[i-1][0] + matrix[i][0] # 完成剩余部分填充 for i in range(1,m): for j in range(1,n): dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + matrix[i][j] return dp[-1][-1] ``` 以上代码片段展示了如何通过构建辅助数来记录每一步的最佳决策过程,并最终返回全局最优解。 #### 复杂度评估 时间复杂度主要取决于遍历整个输入矩阵所需的操作次数,即 O(M*N),这里 M 和 N 分别代表矩阵的高度与宽度。空间复杂度同样为 O(M*N),因为我们需要额外的空间存储中间结果以便后续访问[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值