【扩展GCD】荒岛野人
题目
【题目描述】
克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。

奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?
【输入】
输入文件的第1行为一个整数N(1<=N<=15),即野人的数目。第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=10^6 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
【输出】
输出文件仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。
【样例输出】
3
1 3 4
2 7 3
3 2 1
【样例输出】
6
【提示】
该样例对应于题目描述中的例子。
题解
看完题目后,我忍不住吐槽一句——题目好烂!
题目中说野人群居,但是却又让野人单独居住,这还叫群居吗?!
好了,回归正题。这题一看就知道是一道数学题(废话),直接暴力是肯定不行的(废话)。
可以先枚举m,再枚举所有两个野人的情况,看看他们会不会在有生之年相遇在同一个山洞。
前面的枚举很简单,关键在于如何判断。
设野人 i 和野人 j 在第 x 年相遇,那么可以列出同余方程:
C_i+P_i\cdot x & \equiv C_j+P_j\cdot x & \text{$(mod\space m)$}\\
C_i+P_i\cdot x & =C_j+P_j\cdot x+my & \text{(转化)}\\
P_i\cdot x-P_j\cdot x & =my+C_j-C_i & \text{(移项)}\\
(P_i-P_j)x-my & =Cj-Ci & \text{(化简)}
\end{aligned}
\]
设\(a=P_i-P_j\),\(b=-m\),\(c=C_j-C_i\),就可以把方程转化成以下形式:
ax+by=c
\end{aligned}
\]
怎么样?眼熟吧!这就是扩展GCD!
首先,可以在式子两边同时模\(\cfrac{c}{gcd(a,b)}\)(如果c不能整除gcd(a,b),那么方程无整数解,可直接退出),为什么?因为a和b一定是可以整除gcd(a,b)的,所以ax和by也一定可以整除它,ax+by也必定可以。
所以式子就变成了这个样子:
ax+by&=gcd(a,b)\\
\because gcd(a,b)&=gcd(b,a\mod b)\\
\therefore ax+by&=bx+(a\mod b)y\\
\end{aligned}
\]
所以我们可以逐步递归下去,直到b=0(看下文)。
继续转换,得
ax+by&=bx+(a\mod b)y\\
&=bx+(a-[\frac{a}{b}]b)y\\
&=bx+ay-[\frac{a}{b}]by\\
&=ay+b(x-[\frac{a}{b}]y)
\end{aligned}
\]
其中,[x]表示下取整x
由此,得
\]
然后就可以这样递归下去了。
现在再来谈谈b=0的情况:
当b=0时,式子变成了\(ax=gcd(a,b)\)
显然\(a=gcd(a,b)\)(因为x是整数),即x=1,y=0
以下是扩展GCD的代码:
int exgcd(int a,int b)
{
if(b==0)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b),t;
t=x;x=y;y=t-a/b*y;
return d;
}
注意:扩展GCD的返回值是gcd(a,b)
由于x可能不是非负的最小解,因此我们要把它处理一下
x=x*cc/d%(b/d);
if(x<0) x+=abs(b/d);
前一句可以让x尽可能地靠近0,后一句可以让x非负。
最后判断一下两个野人可不可以在有生之年相遇,即看看是否\(x\le \min(l_i,l_j)\)
这题就搞定了。
代码
#include<cstdio>
using namespace std;
int c[20],p[20],l[20],x,y;
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline int abs(int x){return x<0?0-x:x;}
int exgcd(int a,int b)
{
if(b==0)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b),t;
t=x;x=y;y=t-a/b*y;
return d;
}
int main()
{
int n,m=0,i,j,k,d,a,b,cc;
bool bk;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&c[i],&p[i],&l[i]);
m=max(m,c[i]);
}
for(k=m;k<=1e+6;k++)
{
bk=0;
for(i=1;i<n;i++)
{
for(j=i+1;j<=n;j++)
{
a=p[i]-p[j],b=k,cc=c[j]-c[i];
d=exgcd(a,b);
if(cc%d) continue;
x=x*cc/d%(b/d);
if(x<0) x+=abs(b/d);
if(x<=min(l[i],l[j]))
{
bk=1;
break;
}
}
if(bk) break;
}
if(!bk) break;
}
printf("%d\n",k);
return 0;
}
【扩展GCD】荒岛野人的更多相关文章
- bzoj1407 / P2421 [NOI2002]荒岛野人(exgcd)
P2421 [NOI2002]荒岛野人 洞穴数不超过1e6 ---> 枚举 判断每个野人两两之间是否发生冲突:exgcd 假设有$m$个洞穴,某两人(设为1,2)在$t$时刻发生冲突 那么我们可 ...
- P1516 青蛙的约会和P2421 [NOI2002]荒岛野人
洛谷 P1516 青蛙的约会 . 算是手推了一次数论题,以前做的都是看题解,虽然这题很水而且还交了5次才过... 求解方程\(x+am\equiv y+an \pmod l\)中,\(a\)的最小整数 ...
- UESTC 288 青蛙的约会 扩展GCD
设两只青蛙跳了t步,则此时A的坐标:x+mt,B的坐标:y+nt.要使的他们在同一点,则要满足: x+mt - (y+nt) = kL (p是整数) 化成: (n-m)t + kL = x-y (L ...
- Poj 1061 青蛙的约会(扩展GCD)
题目链接:http://poj.org/problem?id=1061 解题报告:两只青蛙在地球的同一条纬度线上,选取一个点位坐标轴原点,所以现在他们都在同一个首尾相连的坐标轴上,那么他们现在的位置分 ...
- poj 1061 青蛙的约会(扩展gcd)
题目链接 题意:两只青蛙从数轴正方向跑,给出各自所在位置, 和数轴长度,和各自一次跳跃的步数,问最少多少步能相遇. 分析:(x+m*t) - (y+n*t) = p * L;(t是跳的次数,L是a青蛙 ...
- 2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd)
题目链接 分析:打表以后就能发现时卡特兰数, 但是有除法取余. f[i] = f[i-1]*(4*i - 2)/(i+1); 看了一下网上的题解,照着题解写了下面的代码,不过还是不明白,为什么用扩展g ...
- BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS
BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS 题意: 你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p, ...
- 扩展gcd算法
扩展gcd算法 神tm ×度搜索exgcd 打到exg的时候出来ex咖喱棒... 球方程\(ax+by=\gcd(a,b)\)的一个解 如果\(b=0\),那么\(\gcd(a,b)=a\),取\(x ...
- 扩展gcd codevs 1200 同余方程
codevs 1200 同余方程 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 求关 ...
随机推荐
- numpy中np.linalg.norm()求向量、矩阵的范数
np.linalg.norm() # linalg = linear(线性) + algebra(代数), norm表示范数 x_norm = np.linalg.norm(x, ord=None ...
- Windows下安装sass和compass失败的解决办法
sass依赖Ruby,所以,首先得先安装个Ruby sass的安装步骤: 在安装的时候,请勾选Add Ruby executables to your PATH这个选项,添加环境变量,不然以后使用编译 ...
- Luogu P5652 基础博弈练习题 (博弈论、图论)
题目链接 https://www.luogu.org/problem/P5652 题解 好题,想了四小时-- 首先考虑如何判断胜负: 首先假设只有一个柱子,那就是奇败偶胜.不难发现最后一个奇数后面的偶 ...
- While 循环 kotlin(11)
While 循环while 和 do .. while 照常使用 while (x > 0) { x--} do { val y = retrieveData()} while (y != nu ...
- ubuntu 18.04 64bit下如何源码编译安装anbox
1. 准备工作 1.1 安装gcc 7.x版本 sudo apt-get install gcc-7 -y 1.2 安装依赖的库及其工具 sudo apt install build-essentia ...
- Ironic 裸金属管理服务的网络模型
目录 文章目录 目录 Bare-Metal networking in Neutron 核心网络类型 网络拓扑 抽象网络拓扑图 Neutron Implementation Neutron 了解裸金属 ...
- Ceph 的用户管理与认证
目录 文章目录 目录 前言 Ceph 的用户管理 用户管理常规操作 CephX 认证系统 身份认证原理 使用 ceph-authtool 进行密钥环管理 注意事项 前言 常规的身份认证系统无非三点: ...
- ubuntu下wps的安装
(一)安装 1)下载:WPS For Linux http://community.wps.cn/download/ 下载wps-office_10.1.0.5672~a21_amd64.deb 2) ...
- java:LeakFilling(Other)
1.Java项目的API文档如何生成?请将步骤写出. javadoc 源文件名.java; 2.增加package以后,我们在DOS下编译怎么做? javac -d . Test.java 3.Jav ...
- Vuex的认识和简单应用(一)
一.vuex是一个专为vue.js应用程序开发的状态管理模式. 应用场景:1.多个视图依赖于同一个状态2.来自不同视图的行为需要变更同一个状态此时,我们可以把组件的共享状态抽取出来,以一个全局单例模式 ...