【扩展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 求关 ...
随机推荐
- Java 读取模板并生成HTML静态文件实例
原理都很简单,主要是对模板的解析.so,我们先准备一个html模板mb.html,做个文件其中的###title###之类的标签用于程序进行查询替换. HTML code复制代码 <html&g ...
- Pycharm查看源代码的问题
linear = torch.nn.Linear() # 无法查看Linear的源代码 from torch.nn import Linear linear = Linear() # 可以查看Line ...
- js中的事件委托技术
1.什么是事件委托:通俗的讲,时间就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个时间本来是加在某些元素上的,然而你却加到别人身上来做,完成这 ...
- vxWorks下常用的几种延时方法
在应用编程的时候,通常会碰到需要一个任务在特定的延时之后执行一个指定的动作,如等待外设以确保数据可靠,控制扬声器发声时间以及串口通信超时重发等.这就需要利用定时器机制来计量特定长度的时间段. ...
- HearthstoneBot
https://github.com/ChuckFork/HearthstoneBot Sigmund Card game automation framework Hooks game and lo ...
- CentOS7 yum install elasticsearch
首先安装 JDK 环境 # 本机是否已经安装,ElasticSearch 最低支持 jdk 1.7 yum list installed | grep java # 查看 yum 库中的 java 安 ...
- android data binding jetpack VI 清理一些概念。BR 运算表达式
android data binding jetpack VIII BindingConversion android data binding jetpack VII @BindingAdapter ...
- ccf 201712-4 行车路线(70分)
ccf 201712-4 行车路线 解题思路: 首先Dijkstra是基于贪心算法的,即每一次作出的选择都具有贪心选择性.此题由于有“如果连续走小道,小明的疲劳值会快速增加,连续走s公里小明会增加s2 ...
- 【React自制全家桶】八、React动画以及react-transition-group动画库的使用
React动画通常有三种方法实现从易到难为: 1.transition(CSS3自带) 2.animation(CSS3自带) 3.react-transition-group动画库(需要引入插件) ...
- 获取packageName和startActivity
import android import pprint # 获取packageName droid = android.Android(('192.168.1.101', 42250)) droid ...