update
This commit is contained in:
		
							parent
							
								
									c2c24ea8b8
								
							
						
					
					
						commit
						adf9c01090
					
				
							
								
								
									
										1
									
								
								day7/inverse/1.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								day7/inverse/1.in
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | 10 13 | ||||||
							
								
								
									
										10
									
								
								day7/inverse/1.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								day7/inverse/1.out
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | 1 | ||||||
|  | 7 | ||||||
|  | 9 | ||||||
|  | 10 | ||||||
|  | 8 | ||||||
|  | 11 | ||||||
|  | 2 | ||||||
|  | 5 | ||||||
|  | 3 | ||||||
|  | 4 | ||||||
							
								
								
									
										1
									
								
								day7/inverse/2.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								day7/inverse/2.in
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | 1500000 5285237 | ||||||
							
								
								
									
										1500000
									
								
								day7/inverse/2.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1500000
									
								
								day7/inverse/2.out
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										55
									
								
								day7/inverse/inverse.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								day7/inverse/inverse.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | #include<bits/stdc++.h> | ||||||
|  | using namespace std; | ||||||
|  | #define int long long | ||||||
|  | 
 | ||||||
|  | int binExp(int b,int e,int m){ | ||||||
|  |     int r=1; | ||||||
|  |     while(e>0){ | ||||||
|  |         if(e%2==1){ | ||||||
|  |             r=(r*b)%m; | ||||||
|  |         } | ||||||
|  |         b=(b*b)%m; | ||||||
|  |         e=e>>1; | ||||||
|  |     } | ||||||
|  |     return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | int inverse(int a,int p){ | ||||||
|  |     return binExp(a, p-2, p); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef OITEST | ||||||
|  | #endif | ||||||
|  | #ifndef OITEST | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | signed main(signed argc ,char* argv[]){ | ||||||
|  |     cin.sync_with_stdio(false); | ||||||
|  |     cin.tie(0); | ||||||
|  | 
 | ||||||
|  |     int n,p; | ||||||
|  |     #ifdef OITEST | ||||||
|  |     assert(argc==2); | ||||||
|  |     string snum(argv[1]); | ||||||
|  |     string ifilen=snum+".in"; | ||||||
|  |     string ofilen=snum+".out"; | ||||||
|  |     cout<<ifilen<<endl; | ||||||
|  |     ifstream ifile(ifilen.c_str()); | ||||||
|  |     ifstream ofile(ofilen.c_str()); | ||||||
|  |     stringstream ss; | ||||||
|  |     #define cin ifile | ||||||
|  |     #define cout ss | ||||||
|  |     #endif | ||||||
|  |     cin>>n>>p; | ||||||
|  | 
 | ||||||
|  |     for(int i=1;i<=n;i++){ | ||||||
|  |         cout<<inverse(i,p)<<endl; | ||||||
|  |         #ifdef OITEST | ||||||
|  |         int o,a; | ||||||
|  |         ss>>o; | ||||||
|  |         ofile>>a; | ||||||
|  |         assert(o==a); | ||||||
|  |         #endif | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -257,4 +257,156 @@ int main() { | |||||||
|    - 定义 $ a, b, p $ 的值。 |    - 定义 $ a, b, p $ 的值。 | ||||||
|    - 调用 `modDivide` 计算结果并输出。 |    - 调用 `modDivide` 计算结果并输出。 | ||||||
| 
 | 
 | ||||||
| 通过这种方式,你可以在 C++ 中使用费马小定理和快速幂算法实现分数的模运算。如果有其他问题或需要进一步的解释,随时告诉我! | 使用扩展欧几里得算法(Extended Euclidean Algorithm, Exgcd)来求解模逆元也是一种经典且高效的方法,特别是在处理大数时更为优越。接下来,我将详细解释如何使用扩展欧几里得算法来实现分数 \(\frac{a}{b} \mod p\) 的计算,并与快速幂进行比较。 | ||||||
|  | 
 | ||||||
|  | ### 扩展欧几里得算法的原理 | ||||||
|  | 
 | ||||||
|  | 扩展欧几里得算法不仅可以用于求两个数的最大公约数(GCD),还能求出模逆元。对于两个整数 \(a\) 和 \(b\),扩展欧几里得算法可以找到一组整数 \(x\) 和 \(y\),使得: | ||||||
|  | 
 | ||||||
|  | \[ | ||||||
|  | ax + by = \gcd(a, b) | ||||||
|  | \] | ||||||
|  | 
 | ||||||
|  | 当 \(a\) 和 \(b\) 互质时,\(\gcd(a, b) = 1\),因此方程变为: | ||||||
|  | 
 | ||||||
|  | \[ | ||||||
|  | ax + by = 1 | ||||||
|  | \] | ||||||
|  | 
 | ||||||
|  | 在这种情况下,\(x\) 就是 \(a\) 模 \(b\) 的逆元,即: | ||||||
|  | 
 | ||||||
|  | \[ | ||||||
|  | a^{-1} \equiv x \pmod{b} | ||||||
|  | \] | ||||||
|  | 
 | ||||||
|  | ### C++ 实现 | ||||||
|  | 
 | ||||||
|  | 下面是使用扩展欧几里得算法计算分数 \(\frac{a}{b} \mod p\) 的 C++ 实现代码: | ||||||
|  | 
 | ||||||
|  | ```cpp | ||||||
|  | #include <iostream> | ||||||
|  | using namespace std; | ||||||
|  | 
 | ||||||
|  | // 扩展欧几里得算法 | ||||||
|  | long long extendedGCD(long long a, long long b, long long &x, long long &y) { | ||||||
|  |     if (b == 0) { | ||||||
|  |         x = 1; | ||||||
|  |         y = 0; | ||||||
|  |         return a; | ||||||
|  |     } | ||||||
|  |     long long x1, y1; | ||||||
|  |     long long gcd = extendedGCD(b, a % b, x1, y1); | ||||||
|  |     x = y1; | ||||||
|  |     y = x1 - (a / b) * y1; | ||||||
|  |     return gcd; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 求 b 的逆元,前提是 b 和 p 互质 | ||||||
|  | long long modInverse(long long b, long long p) { | ||||||
|  |     long long x, y; | ||||||
|  |     long long g = extendedGCD(b, p, x, y); | ||||||
|  |     if (g != 1) { | ||||||
|  |         throw invalid_argument("Inverse doesn't exist."); | ||||||
|  |     } else { | ||||||
|  |         // 确保结果是正数 | ||||||
|  |         return (x % p + p) % p; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 计算 (a / b) % p | ||||||
|  | long long modDivide(long long a, long long b, long long p) { | ||||||
|  |     long long inv = modInverse(b, p); | ||||||
|  |     return (a * inv) % p; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int main() { | ||||||
|  |     long long a = 10, b = 3, p = 7; | ||||||
|  |     try { | ||||||
|  |         long long result = modDivide(a, b, p); | ||||||
|  |         cout << "Result of " << a << "/" << b << " mod " << p << " is: " << result << endl; | ||||||
|  |     } catch (const invalid_argument &e) { | ||||||
|  |         cout << e.what() << endl; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### 逐行解释 | ||||||
|  | 
 | ||||||
|  | 1. **扩展欧几里得算法**: | ||||||
|  | 
 | ||||||
|  |    ```cpp | ||||||
|  |    long long extendedGCD(long long a, long long b, long long &x, long long &y) { | ||||||
|  |        if (b == 0) { | ||||||
|  |            x = 1; | ||||||
|  |            y = 0; | ||||||
|  |            return a; | ||||||
|  |        } | ||||||
|  |        long long x1, y1; | ||||||
|  |        long long gcd = extendedGCD(b, a % b, x1, y1); | ||||||
|  |        x = y1; | ||||||
|  |        y = x1 - (a / b) * y1; | ||||||
|  |        return gcd; | ||||||
|  |    } | ||||||
|  |    ``` | ||||||
|  | 
 | ||||||
|  |    - 当 \(b = 0\) 时,直接返回 \(a\) 作为 gcd,设 \(x = 1\) 和 \(y = 0\)。 | ||||||
|  |    - 递归调用 `extendedGCD(b, a % b, x1, y1)`,计算 gcd 及其对应的系数。 | ||||||
|  |    - 通过回溯,计算当前的 \(x\) 和 \(y\)。 | ||||||
|  | 
 | ||||||
|  | 2. **求模逆元**: | ||||||
|  | 
 | ||||||
|  |    ```cpp | ||||||
|  |    long long modInverse(long long b, long long p) { | ||||||
|  |        long long x, y; | ||||||
|  |        long long g = extendedGCD(b, p, x, y); | ||||||
|  |        if (g != 1) { | ||||||
|  |            throw invalid_argument("Inverse doesn't exist."); | ||||||
|  |        } else { | ||||||
|  |            return (x % p + p) % p; | ||||||
|  |        } | ||||||
|  |    } | ||||||
|  |    ``` | ||||||
|  | 
 | ||||||
|  |    - 使用扩展欧几里得算法计算 \(b\) 的模逆元 \(x\)。 | ||||||
|  |    - 如果 gcd 不为 1,则 \(b\) 和 \(p\) 不互质,逆元不存在。 | ||||||
|  |    - 否则,返回 \(x\) 的正值作为逆元。 | ||||||
|  | 
 | ||||||
|  | 3. **计算 \(\frac{a}{b} \mod p\)**: | ||||||
|  | 
 | ||||||
|  |    ```cpp | ||||||
|  |    long long modDivide(long long a, long long b, long long p) { | ||||||
|  |        long long inv = modInverse(b, p); | ||||||
|  |        return (a * inv) % p; | ||||||
|  |    } | ||||||
|  |    ``` | ||||||
|  | 
 | ||||||
|  |    - 调用 `modInverse` 求出 \(b\) 的逆元 \(inv\)。 | ||||||
|  |    - 返回 \( (a \times inv) \mod p \)。 | ||||||
|  | 
 | ||||||
|  | 4. **主函数**: | ||||||
|  | 
 | ||||||
|  |    ```cpp | ||||||
|  |    int main() { | ||||||
|  |        long long a = 10, b = 3, p = 7; | ||||||
|  |        try { | ||||||
|  |            long long result = modDivide(a, b, p); | ||||||
|  |            cout << "Result of " << a << "/" << b << " mod " << p << " is: " << result << endl; | ||||||
|  |        } catch (const invalid_argument &e) { | ||||||
|  |            cout << e.what() << endl; | ||||||
|  |        } | ||||||
|  |        return 0; | ||||||
|  |    } | ||||||
|  |    ``` | ||||||
|  | 
 | ||||||
|  |    - 定义 \(a, b, p\) 的值,计算并输出结果。 | ||||||
|  | 
 | ||||||
|  | ### 为什么使用 Exgcd ? | ||||||
|  | 
 | ||||||
|  | 相比于快速幂算法,Exgcd 在某些场景下更加灵活和高效: | ||||||
|  | 
 | ||||||
|  | 1. **处理更大范围的数**:Exgcd 可以直接处理整数(包括负数),而快速幂需要在计算中额外处理这些情况。 | ||||||
|  | 2. **无需质数模**:快速幂算法基于费马小定理,只能在模数为质数的情况下使用。而 Exgcd 不要求模数为质数。 | ||||||
|  | 3. **更快的计算速度**:对于某些特定的输入,Exgcd 在常数时间上可能更快。 | ||||||
|  | 
 | ||||||
|  | 通过这种方式,你可以在 C++ 中使用扩展欧几里得算法来实现高效的分数模运算。如果你还有其他问题或需要进一步的解释,随时告诉我! | ||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										11
									
								
								xmake.lua
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								xmake.lua
									
									
									
									
									
								
							| @ -37,4 +37,13 @@ target("fperfect") | |||||||
| 
 | 
 | ||||||
| target("pre88") | target("pre88") | ||||||
|     set_kind("binary") |     set_kind("binary") | ||||||
|     add_files("./day6/pre88/*.cpp") |     add_files("./day6/pre88/*.cpp") | ||||||
|  | 
 | ||||||
|  | target("inverse") | ||||||
|  |     set_kind("binary") | ||||||
|  |     add_files("./day7/inverse/*.cpp") | ||||||
|  |     set_rundir("./day7/inverse") | ||||||
|  |     for v=1,2 do  | ||||||
|  |         local strname = tostring(v) | ||||||
|  |         add_tests(strname,{files="./day7/inverse/*.cpp",defines="OITEST",runargs=strname,run_timeout=1000}) | ||||||
|  |     end | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user