P4777 【模板】扩展中国剩余定理(EXCRT)、P3846 [TJOI2007] 可爱的质数/【模板】BSGS、P4195 【模板】扩展 BSGS/exBSGS

P4777 【模板】扩展中国剩余定理(EXCRT)

题目描述

P4777 【模板】扩展中国剩余定理(EXCRT) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

运行代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

typedef __int128 LL;
const int N = 100005;
LL n, m[N], r[N];

LL exgcd(LL a,LL b,LL &x,LL &y){
  if(b==0){x=1, y=0; return a;}
  LL d, x1, y1;
  d = exgcd(b, a%b, x1, y1);
  x = y1, y = x1-a/b*y1;
  return d;
}
LL EXCRT(LL m[], LL r[]){
  LL m1, m2, r1, r2, p, q;
  m1 = m[1], r1 = r[1];
  for(int i=2; i<=n; i++){
    m2 = m[i], r2 = r[i];
    LL d = exgcd(m1,m2,p,q);
    if((r2-r1)%d){return -1;}
    p=p*(r2-r1)/d; //特解
    p=(p%(m2/d)+m2/d)%(m2/d);
    r1 = m1*p+r1;
    m1 = m1*m2/d;
  }
  return (r1%m1+m1)%m1;
}
int main(){
  scanf("%lld", &n);
  for(int i = 1; i <= n; ++i)
    scanf("%lld%lld", m+i, r+i);
  printf("%lld\n",EXCRT(m,r));
  return 0;
}

代码思路

  1. 定义了一些必要的变量和常量,包括 __int128 类型的 LL 用于处理大整数,以及数组 m 和 r 来存储问题中的模数和余数。

  2. exgcd 函数是扩展欧几里得算法,用于计算两个数的最大公约数 d 以及满足贝祖等式的系数 x 和 y 。

  3. EXCRT 函数是求解中国剩余定理(Chinese Remainder Theorem,CRT)的核心函数:

    • 首先初始化 m1 和 r1 为第一组模数和余数。
    • 然后通过循环处理后续的每组模数和余数:计算当前处理的两组模数 m1 和 m2 的最大公约数 d 。检查当前两组余数的差 (r2 - r1) 是否能被 d 整除,如果不能则表示无解,返回 -1 。计算满足方程的特解 p 。更新新的余数 r1 和模数 m1 。
  4. 在 main 函数中:读取输入的组数 n 。取每组的模数和余数。调用 EXCRT 函数求解并输出结果。

P3846 [TJOI2007] 可爱的质数/【模板】BSGS

题目描述

P3846 [TJOI2007] 可爱的质数/【模板】BSGS - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

运行代码

#include<iostream>
#include<algorithm>
using namespace std;
#include<unordered_map>
typedef long long ll;
ll bsgs(ll a, ll b, ll p) {
	a %= p; b %= p;
	if (b == 1)return 0;
	ll m = ceil(sqrt(p));
	ll t = b;
	unordered_map<int, int>hash;
	hash[b] = 0;
	for (int j = 1; j < m; j++) {
		t = t * a % p;
		hash[t] = j;
	}
	ll mi = 1;
	for (int i = 1; i <= m; i++)
		mi = mi * a % p; //求a^m
	t = 1;
	for (int i = 1; i <= m; i++) {
		t = t * mi % p; //求(a^m)^i
		if (hash.count(t))
			return i * m - hash[t];
	}
	return -1; //无解
}
int main() {
	int a, p, b;
	cin >> p >> a >> b;
	int res = bsgs(a, b, p);
	if (res == -1) puts("no solution");
	else cout << res << endl;
	return 0;
}

代码思路

  1. 定义了 bsgs 函数用于求解形如 a^x ≡ b (mod p) 的离散对数问题。

  2. 在函数内部:

    • 首先对 a 和 b 取模 p ,进行预处理。
    • 如果 b 模 p 后等于 1 ,直接返回 0 。
    • 计算一个步长 m ,约为 p 的平方根向上取整。
    • 然后通过一个循环计算 b * a^j (j = 0 到 m - 1) 的值,并将其和对应的索引 j 存入哈希表 hash 中。
    • 计算 a^m 并赋值给 mi 。
    • 再通过一个循环计算 (a^m)^i ,并检查其是否在之前的哈希表中。如果在,就返回计算得到的结果。
    • 如果整个过程都没有找到解,返回 -1 。
  3. 在 main 函数中:读取输入的 p 、 a 和 b 。调用 bsgs 函数求解,并根据结果输出相应的信息。如果结果为 -1 ,输出 "no solution" ,否则输出计算得到的解。

总的来说,这段代码的思路是通过分块和哈希表来加速对离散对数问题的求解。

P4195 【模板】扩展 BSGS/exBSGS

题目描述

P4195 【模板】扩展 BSGS/exBSGS - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

运行代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <unordered_map>
using namespace std;

typedef long long LL;

LL gcd(LL a, LL b){
  return b==0?a:gcd(b,a%b);
}
LL exbsgs(LL a, LL b, LL p){
  a %= p; b %= p;
  if(b==1||p==1)return 0;//x=0
  
  LL d, k=0, A=1;
  while(true){
    d = gcd(a,p);
    if(d==1) break;
    if(b%d) return -1; //无解
    k++; b/=d; p/=d;
    A = A*(a/d)%p; //求a^k/D
    if(A==b) return k;
  }
  
  LL m=ceil(sqrt(p));
  LL t = b;
  unordered_map<int,int> hash;
  hash[b] = 0;
  for(int j = 1; j < m; j++){
    t = t*a%p; //求b*a^j
    hash[t] = j;
  }
  LL mi = 1;
  for(int i = 1; i <= m; i++)
    mi = mi*a%p; //求a^m
  t = A;
  for(int i=1; i <= m; i++){
    t = t*mi%p; //求(a^m)^i
    if(hash.count(t)) 
      return i*m-hash[t]+k;
  }
  return -1; //无解
}
int main(){
  LL a, p, b;
  while((scanf("%lld%lld%lld",&a,&p,&b)!=EOF)&&a){
    LL res = exbsgs(a, b, p);
    if(res == -1) puts("No Solution");
    else printf("%lld\n",res);
  }
  return 0;
}

代码思路

  1. gcd 函数:这是一个递归实现的求最大公约数的函数,使用欧几里得算法。

  2. exbsgs 函数:

    • 首先对输入的 ab 进行模 p 的处理。
    • 如果 b 为 1 或者 p 为 1,直接返回 0
    • 然后进入一个循环,不断计算 a 和 p 的最大公约数 d 。
    • 如果 b 不能被 d 整除,说明无解,返回 -1 。
    • 否则更新 k 、b 、p 和 A 的值。如果 A 等于 b,返回 k 。
    • 计算一个步长 m ,约为 p 的平方根向上取整。
    • 接着创建一个哈希表,通过循环计算并存储 b * a^j (j = 0 到 m - 1) 的值和对应的索引。
    • 计算 a^m 并赋值给 mi 。
    • 再通过一个循环计算 A * (a^m)^i ,并检查其是否在之前的哈希表中。如果在,返回计算得到的结果,即 i*m - hash[t] + k 。
    • 如果整个过程都没有找到解,返回 -1 。
  3. main 函数:不断读取输入的 ap 和 b ,只要 a 不为 0 。调用 exbsgs 函数求解,并根据结果输出相应的信息。如果结果为 -1 ,输出 "No Solution" ,否则输出计算得到的解。

这段代码的主要目的是通过扩展的 Baby Step Giant Step 算法来求解形如 a^x ≡ b (mod p) 的离散对数问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱姌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值