荒岛野人(题解)

题目描述


克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。
奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?

Solution


我们会发现,这题和青蛙的约会有一点相像,很显然是exgcd的应用题。
首先我们读完题目可以列出一个等式:
C + P C + x P ( m o d m )
显然我们只要让这个等式无解,就能满足野人永远追不上,而且野人是有寿命的,就是不需要永远无解。

在中间计算初始编号的差值时有可能出现负数,我们需要加一个绝对值,不然会超时(很难受)

代码:

 //By Bibi
///                 .-~~~~~~~~~-._       _.-~~~~~~~~~-.
///             __.'              ~.   .~              `.__
///           .'//                  \./                  \\`.
///        .'//                     |                     \\`.
///       .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
///     .'//.-"                 `-.  |  .-'                 "-.\\`.
///   .'//______.============-..   \ | /   ..-============.______\\`.
/// .'______________________________\|/______________________________`.
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int MAXN=17;
int read(){
    int sum=0,flag=1;
    char c;
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
    for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
    return sum*flag;
}
int n;
int c[MAXN],p[MAXN],l[MAXN];
int maxx;
int gcd(int a,int b){
    return b? gcd(b,a%b):a;
}
int exgcd(int a,int b,int &x,int &y){
    if(!b) {x=1;y=0;return a;}
    else {
        int d=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
}
void init(){
    n=read();
    rep(i,1,n) c[i]=read(),p[i]=read(),l[i]=read(),maxx=max(maxx,c[i]);
}
bool work(int m){
    int a,b,C,t,x,y;
    rep(i,1,n){
        rep(j,i+1,n){
            a=p[i]-p[j];
            C=c[j]-c[i];
            b=m;
            t=gcd(a,b);
            if(C%t==0){
                a/=t,b/=t,C/=t;
                exgcd(a,b,x,y);
                b=abs(b);
                x=((C*x)%b+b)%b;
                if(!x) x+=b;
                if(x<=min(l[i],l[j])) return 0;
            }
        }
    }
    return 1;
}
int main(){
    init();
    for(int i=maxx;;++i){
        if(work(i)) {printf("%d",i);return 0;}
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bbbblzy/article/details/80472160