[NOI2002] Savage 解题报告(扩展欧几里得)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1407

Description

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

 

奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?
 

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。
 

Sample Input

3 1 3 4 2 7 3 3 2 1

Sample Output

6

比赛的时候写这题我写了个瞎二分,然后最后半个小时发现不满足二分性质,就又随性的加上了枚举,于是...得到了20分的安慰分

好吧其实正解就是枚举,我们从小到大枚举山洞的个数

怎么判断是否会有野人相遇呢?若有m个山洞,对于野人i,j,他们相遇的充要条件就是:

Ci+xPi≡Cj+xPj (mod m)

移项可得:Ci-Cj≡x(Pj-Pi) (mod m)

于是我们设 x(Pj-Pi)+ym=Ci-Cj

设A=Pj-Pi B=m C=Ci-Cj,考虑解不定方程Ax+By=C

对于x的最小正整数解,若满足x<=min(L[i],L[j]),那么两个野人就可以在有生之年相遇

既然这样,我们依次枚举两个野人就好

怎么解不定方程...就不说了

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=25;
int n,minc;
int c[maxn],p[maxn],l[maxn];
int gcd(int x,int y) {if (x%y==0) return y;else return gcd(y,x%y);}
void exgcd(int A,int B,int &x,int &y)
{
    if (!B)
    {
        x=1;y=0;return;
    }
    exgcd(B,A%B,x,y);
    int z=x;x=y;y=z-y*(A/B);
}
bool check(int t)
{
    for (int i=1;i<=n;i++)
    {
        for (int j=i+1;j<=n;j++)
        {
            int A=p[i]-p[j],B=t,C=c[j]-c[i],x,y;    
            int gg=gcd(A,B);
            if (C%gg==0)
            {
                A/=gg;B/=gg;C/=gg;
                exgcd(A,B,x,y);
                B=abs(B);
                x=((x*C)%B+B)%B;
                while (!x) x+=B;
                if (x<=min(l[i],l[j])) return 0;
            }
        }
    }
    return 1;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
    scanf("%d%d%d",c+i,p+i,l+i);
    minc=max(minc,c[i]);
    }
    for (int t=minc;;t++) if (check(t)) {printf("%d",t);break;}
    return 0;
}
原文地址:https://www.cnblogs.com/xxzh/p/9287006.html