暑假集训8.6数论专题—Savage(扩展欧几里得算法)

本文探讨了一个涉及野人洞穴分配的问题,并通过模运算和扩展欧几里得算法提供了解决方案。文章详细阐述了算法的实现过程,包括如何通过逆向思考来确定最少可能的山洞数量,以及如何利用模运算和扩展欧几里得算法来判断洞穴之间的合法关系。通过逐步枚举可能的山洞数量,确保最终得到的解是最优的。

题目描述:

Input

  第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
(1<=Ci,Pi<=100, 0<=Li<=10^6 ) 
 
Output
仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。
 
题解:
 因为围成一个环因此能想到mod,接着我们可以你逆向思考,当ci+pi*x≡cj+pj*x(mod ans)存在时,ans不合法,由于数据较小,且不满足二分性质,我们可以由小到大枚举ans的大小,将式子化成(pi-pj)*x+ans*y=cj-ci,根据这个式子可以用扩展欧几里得解除x,根据x与li,lj的关系判断x是否合法。
 
关于扩展欧几里得:
上板子!
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){x=1;y=0;return a;}
    LL t=exgcd(b,a%b,x,y);LL x1=x;
    x=y;y=x1-a/b*y;
    return t;
}
View Code

整题完整代码如下:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=17;
int n,p[N],c[N],l[N],m;
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;return f*x;}
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){x=1;y=0;return a;}
    LL t=exgcd(b,a%b,x,y);
    LL x1=x;x=y;y=x1-a/b*y;return t;
}
il bool check(LL m){
    LL x,y,g;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            g=exgcd((LL)(p[i]-p[j]),m,x,y);
            if(((c[j]-c[i])%g+g)%g)continue;
            x=x*(LL)(c[j]-c[i])/g;g=abs(g);
            x=(x%(m/g)+(m/g))%(m/g);
            if(x<=l[i]&&x<=l[j])return 0;
        }
    return 1;
}
int main()
{
    n=read();for(int i=1;i<=n;i++)c[i]=read(),p[i]=read(),l[i]=read(),m=max(m,c[i]);
    while(!check((LL)m))m++;printf("%d\n",m);
  return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Jessie-/p/9434449.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值