P5345 【XR-1】快乐肥宅

Preface

好题!!!

当然也很毒瘤。

突然感到屠龙勇士在这题面前

就是逊内!!!

Description

给定高次同余方程组
{ k 1 x ≡ r 1 ( m o d g 1 ) k 2 x ≡ r 2 ( m o d g 2 ) ⋯ k n x ≡ r n ( m o d g n ) \begin{cases} k_1^x\equiv r_1\pmod {g_1}\\ k_2^x\equiv r_2\pmod {g_2}\\ \cdots\\ k_n^x\equiv r_n\pmod {g_n} \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧​k1x​≡r1​(modg1​)k2x​≡r2​(modg2​)⋯knx​≡rn​(modgn​)​
请求出该方程组的最小 非负 整数解,若 无解最小解 ≥ 1 0 9 \ge 10^9 ≥109,输出 Impossible

  • 对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 3 1 \le n \le 10^3 1≤n≤103, 1 ≤ k i , r i ≤ g i ≤ 1 0 7 1 \le k_i, r_i \le g_i \le 10^7 1≤ki​,ri​≤gi​≤107。

Solution

前置芝士:

  • exBSGS
  • exCRT

一、求出单个同余方程的解

对于 a x m o d p a^x\bmod p axmodp,结果应该分为一段“尾巴”和一段循环部分,例如 12 4 x m o d 495616 124^x\bmod 495616 124xmod495616:

感谢兔队的图

这时对于一个正整数 b b b, a x ≡ b ( m o d p ) a^x\equiv b\pmod p ax≡b(modp) 的解有 3 3 3 种情况:

  • 唯一解:即 x x x 在尾巴上。例如 b = 15376 b=15376 b=15376 时, x = 2 x=2 x=2。
  • 无穷解:即 x x x 在循环上。例如 b = 241664 b=241664 b=241664 时, x ≡ 3 + 5 ( m o d 5 ) x\equiv 3+5\pmod 5 x≡3+5(mod5) 且 x ≥ 3 + 5 x\ge 3+5 x≥3+5,其中 3 3 3 表示 b b b 是循环中的第 3 3 3 个, + 5 +5 +5 表示尾巴的长度,模数为 5 5 5 表示循环的长度,不等式是为了保证 x x x 在循环上。
  • 无解:例如 b = 114514 b=114514 b=114514 时。

exBSGS 中,除到 gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1 时,先用 BSGS 求出 a x ≡ b ( m o d p ) a^x\equiv b\pmod p ax≡b(modp) 的最小非负整数解,再求出 a a a 模 p p p 的阶( gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1 时阶一定存在),那么阶就是循环长度。

下面的代码返回一个 pair ⁡ \operatorname{pair} pair,第一个数表示最小解(如果无解则为 − 1 -1 −1),第二个数表示阶(如果不存在则为 − 1 -1 −1)。

exBSGS 模板一样,需要特判 b = 1 b=1 b=1 或 p = 1 p=1 p=1 的情况。

pair<int, int> exBSGS(int a, int b, int p)
{if (p == 1){return make_pair(0, 1);}a %= p, b %= p;int g = exgcd(a, p), f = 1, k = 0;while (g > 1){if (b % g){if (b == 1){return make_pair(0, -1);}return make_pair(-1, -1);}k++;b /= g, p /= g;f = (ll)f * (a / g) % p;g = exgcd(a, p);if (f == b){if (g > 1){return make_pair(k, -1);}int y = BSGS(a, 1, p);return make_pair(k, y);}}int x = BSGS(a, (ll)b * inv(f, p) % p, p);if (x == -1){return make_pair(-1, -1);}int y = BSGS(a, 1, p);return make_pair(x % y + k, y);
}

在主函数中:

pair<int, int> res = exBSGS(k, r, g);
b[i] = res.first, a[i] = res.second;
if (b[i] == -1) // x 无解就肯定无解
{puts("Impossible");return 0;
}
else if (a[i] == -1) // 阶不存在,用一个 X 记录唯一的解
{X = b[i];continue;
}
mn = max(mn, b[i]); // x ≥ mn

二、合并解

如果出现了唯一解(即上面代码中的 X ≠ − 1 X\ne -1 X​=−1)的情况,直接将这个 X X X 带入剩下的方程中检验即可。

否则直接用 exCRT 合并即可,注意要加上 lcm ⁡ ( a 1 , a 2 , … , a n ) \operatorname{lcm}(a_1,a_2,\dots,a_n) lcm(a1​,a2​,…,an​) 的倍数使得答案不小于上面代码中的 m n mn mn。

我们设前 ( i − 1 ) (i-1) (i−1) 个方程组合并后的解为 x ≡ B ( m o d A ) x\equiv B\pmod A x≡B(modA),第 i i i 个方程为 x ≡ b ( m o d a ) x\equiv b\pmod a x≡b(moda)。

问题来了, 1 0 3 10^3 103 个 1 0 7 10^7 107,合并后 A , B A,B A,B 都有可能爆 long long

观察题目中的要求:

若无解或 最小解 ≥ 1 0 9 \ge 10^9 ≥109,输出 Impossible

当 A > 1 0 9 A>10^9 A>109 时,直接检测 B B B 是否满足 B ≡ b ( m o d a ) B\equiv b\pmod a B≡b(moda) 即可,如果不满足那么一定要加上若干个 A A A,那么一定超过了 1 0 9 10^9 109,不满足要求。

全部合并完之后记得也要判断 B B B 是否在 1 0 9 10^9 109 内。

Code

//18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#include <map>
#include <cmath>
#define Debug(x) cout << #x << "=" << x << endl
typedef long long ll;
using namespace std;ll x, y;ll exgcd(ll a, ll b)
{if (!b){x = 1, y = 0;return a;}ll Gcd = exgcd(b, a % b);ll tmp = x;x = y;y = tmp - a / b * y;return Gcd;
}ll A, B;int merge(ll a, ll b)
{ll Gcd = exgcd(A, a), c = B - b;if (c % Gcd){return -1;}c /= Gcd;x = (x * c % a + a) % a;ll Lcm = A / Gcd * a;B = (B - A * x % Lcm + Lcm) % Lcm;A = Lcm;return 1;
}int div_ceil(int a, int b)
{return (a - 1) / b + 1;
}const int MAXN = 1e3 + 5;
const int D = 1e9;int a[MAXN], b[MAXN];int exCRT(int n, int mn)
{A = a[1], B = b[1];for (int i = 2; i <= n; i++){if (A > D && (B - b[i]) % a[i]){return -1;}else if (A <= D && merge(a[i], b[i]) == -1){return -1;}}if (B < mn){B += div_ceil(mn - B, A) * A;}if (B > D){return -1;}return B;
}int inv(int a, int p)
{exgcd(a, p);x = (x % p + p) % p;return x;
}int phi(int p)
{int ans = p;for (int i = 2; i * i <= p; i++){if (p % i == 0){ans = ans / i * (i - 1);while (p % i == 0){p /= i;}}}if (p != 1){ans = ans / p * (p - 1);}return ans;
}int BSGS(int a, int b, int p)
{map<int, int> hash;int t = ceil(sqrt(phi(p))), aj = 1;for (int j = 0; j < t; j++){int val = (ll)b * aj % p;hash[val] = j;aj = (ll)aj * a % p;}a = aj;int ai = 1;for (int i = 1; i <= t; i++){ai = (ll)ai * a % p;if (hash.find(ai) != hash.end()){int j = hash[ai];if (i * t - j >= 0){return i * t - j;}}}return -1;
}pair<int, int> exBSGS(int a, int b, int p)
{if (p == 1){return make_pair(0, 1);}a %= p, b %= p;int g = exgcd(a, p), f = 1, k = 0;while (g > 1){if (b % g){if (b == 1){return make_pair(0, -1);}return make_pair(-1, -1);}k++;b /= g, p /= g;f = (ll)f * (a / g) % p;g = exgcd(a, p);if (f == b){if (g > 1){return make_pair(k, -1);}int y = BSGS(a, 1, p);return make_pair(k, y);}}int x = BSGS(a, (ll)b * inv(f, p) % p, p);if (x == -1){return make_pair(-1, -1);}int y = BSGS(a, 1, p);return make_pair(x % y + k, y);
}int main()
{int n;scanf("%d", &n);int mn = 0, X = -1;for (int i = 1; i <= n; i++){int k, g, r;scanf("%d%d%d", &k, &g, &r);pair<int, int> res = exBSGS(k, r, g);b[i] = res.first, a[i] = res.second;if (b[i] == -1){puts("Impossible");return 0;}else if (a[i] == -1){X = b[i];continue;}mn = max(mn, b[i]);}if (X != -1){for (int i = 1; i <= n; i++){if ((a[i] == -1 && X != b[i]) || (a[i] != -1 && (X < b[i] || (X - b[i]) % a[i]))){puts("Impossible");return 0;}}printf("%d\n", X);return 0;}int ans = exCRT(n, mn);if (ans == -1){puts("Impossible");}else{printf("%d\n", ans);}return 0;
}

References

  • [1] 小粉兔:洛谷 P5345: 【XR-1】快乐肥宅

【题解】Luogu-P5345 【XR-1】快乐肥宅相关推荐

  1. 计算机硬件专业知识西瓜视频,2019年中电脑硬件榜单,空调西瓜+电脑助你当个快乐肥宅...

    原标题:2019年中电脑硬件榜单,空调西瓜+电脑助你当个快乐肥宅 空调+WiFi+西瓜+电脑=快乐肥宅. 又是一年毕业季和高考季结束了,暑假迎来了购机换机高峰期.此时入手一台性能强劲的电脑主机,让你成 ...

  2. Arduino实例2——快乐肥宅机

    最近发现了两个特别有趣的传感器,一个是巡线传感器,一个是非接触式液位传感器. 有一次,我在思考有什么传感器能够检测到前面很近的距离是否有阻挡时,或者是在传送带上检测面前是否有需要处理的工件的时候,看了 ...

  3. 快乐肥宅水--辗转相除法

    题目描述 算法协会有三个主要部门,算法组.项目组和事务组.现在指导老师CD想为大家发福利,给每个组发若干瓶肥宅快乐水,要求各组得到的肥宅快乐水数量相同,并且各组内能够按人数平分(每人至少分一瓶).现在 ...

  4. 1024程序员节公司福利哪家强?小米贺卡纪念币,脉脉快乐肥宅鸡

    也许有人不懂 1024 为啥是程序员节,这里简单普及下吧.1024 最初源自于一个论坛,他的回帖机制是,新用户发过帖之后,过 1024 秒之后才能再发一帖.我们知道,程序员是跟计算机打交道的,而一般计 ...

  5. 肥宅有理?大数据帮你找到不去健身房的原(jie)因(kou)

    作者 宋宇 赵玮雯 来源 DT财经 原创作品,如有转载,请联系公众号授权. 扪心自问,是什么拖住了你奔往健身房的腿?数据给出的理由能让你心服口吗? A4腰.马甲线,让你成功反手摸肚脐--这些词已经不火 ...

  6. 肥宅快乐还是不快乐,拓展欧几里得,exgcd???bfs

    扩展欧几里德算法 先介绍什么叫做欧几里德算法有两个数 a b,现在,我们要求 a b 的最大公约数,怎么求?枚举他们的因子?不现实,当 a b 很大的时候,枚举显得那么的naïve ,那怎么做?欧几里 ...

  7. 平分肥宅快乐水(C++)

    #include<bits/stdc++.h> using namespace std; int main(){double t;int n;cin>>t>>n;p ...

  8. 【愚公系列】2021年11月 攻防世界-进阶题-MISC-055(肥宅快乐题)

    文章目录 一.肥宅快乐题 二.答题步骤 1.视频播放器 2.base64 总结 一.肥宅快乐题 题目链接:https://adworld.xctf.org.cn/task/task_list?type ...

  9. 喜迎儿童节,肥宅快乐码。

    发现编辑器不能插入视频音频资源,完整版请查看原文链接:http://dopro.io/morse.html 上周是六月一日儿童节.很多小朋友大朋友们都拥有了自己的"肥宅快乐套餐", ...

最新文章

  1. 简单BP网络识别数码表字符
  2. limit实现原理 mysql_值得一生典藏:MySQL的事务实现原理
  3. Selenium基础知识
  4. LeetCode 848. 字母移位(前缀和+取模)
  5. 讲个故事为什么IP地址与Mac地址缺一不可?
  6. Embree:照片级光线追踪内核
  7. php 中 date转换为字符串,PHP 时间与字符串的相互转化
  8. python实现寻找最长回文子序列
  9. “云湖共生 • 数智未来”数据湖应用实践白皮书重磅发布
  10. matlab中idwt,matlab图片处理
  11. 微信小程序轮播图调用接口
  12. linux iso镜像安装工具,教你制作属于自己的CentOS 6.4一键自动化安装ISO镜像光盘...
  13. 小白轻松使用axis2构建webservice
  14. html js 在文本框选择自动计算乘,怎么让JS实现在文本框中输入数字时,同时输出这个数字,并再输出一个乘以0.39的值?...
  15. 题目:身份证录入系统 一、语言和环境 a)实现语言Java, 使用Android开发环境实现《身份证录入系统》APP。具体要求如下: 打开应用后,显示效果如图-1所示:
  16. DIY个人智能家庭网关—— 路由器篇之安装python
  17. 2020-02-24 RK3288 Android7.1 5.1 增加AP6256 WI-FI Bluetooth调试记录
  18. 华为NCE网管创建EVPL(共享VCTrunk) 路径法三步走
  19. 计算机基础职高重点知识总结,职高计算机应用基础课浅议
  20. powerdesigner中cmd模型中多对多_沙盘模型中的建筑模型比例缩放

热门文章

  1. 人大金仓数据库.net core 开发接口
  2. sparksql获取partitions信息(show partitions只能展示不能被条件调用)
  3. 习语言控制台程序示例
  4. Java三大结构 顺序结构、选择结构、循环结构
  5. 从零开始IntelliJ IDEA
  6. 孤独并快乐,我在十八线小城市做开源
  7. 星系测光:理论基础与实操
  8. 基于网格的聚类STING、CLIQUE(机器学习)
  9. 大数据的理论基础是什么
  10. 大数据平台搭建详细流程(一)框架简介与平台准备