• 洛谷P2421 [NOI2002]荒岛野人(扩展欧几里得)


    题目背景

    原 A-B数对(增强版)参见P1102

    题目描述

    克里特岛以野人群居而著称。岛上有排列成环行的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<=106 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。

    输出格式:

    仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。

    输入输出样例

    输入样例#1: 复制
    3
    1 3 4
    2 7 3
    3 2 1
    输出样例#1: 复制
    6

    说明

    对于50% 的数据:N 的范围是[1…1,000]。

    对于另外50% 的数据:N 的范围是[1…100,000]。

    对于100% 的数据:C 的范围是[1…1,000,000,000],N 个整数中每个数的范围是:[0…1,000,000,000]。

    我居然切了一道紫题??!!好开心qwq

    设第$i$个人的寿命为$x_i$,每次走$y_i$,刚开始在$a$,

    若洞穴数为$b$,那么我们需要找到最小的$b$满足对于任意的两个野人$i,j$

    $a_i+y_i * T_i ot equiv a_j + y_j + T_j pmod b$,$T$表示第几年。

    然后这个是个标准的欧几里得式子

    枚举一个$b$,判断就好了

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int MAXN = 16, B = 31;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N;
    struct Node {
        int bg, step, life;
        bool operator < (const Node &rhs) const {
            return this -> step < rhs.step;
        }
    }a[MAXN];
    int x, y;
    int exgcd(int a, int b, int &x, int &y) {
        if(b == 0) {
            x = 1, y = 0; return a;
        }
        int r = exgcd(b, a % b, x, y);
        int tmp = x; x = y, y = tmp - (a / b) * y;
        return r;
    }
    bool check(int X) {
        for(int i = 1; i <= N; i++) {
            for(int j = 1; j <= i - 1; j++) {    
                int B = X;
                int A = a[i].step - a[j].step, C = a[j].bg - a[i].bg, r = __gcd(A, B);
                if(C % r != 0) continue;
                A = A / r; B = B / r; C = C / r;
                exgcd(A, B, x, y);
                x = (x * C) % B;
                while(x < 0) x += B;
                if(x <= a[i].life && x <= a[j].life) return 0;
            }
        }
        return 1;
    }
    main() { 
    #ifdef WIN32
        freopen("a.in", "r", stdin);
    #endif
        N = read();
        int fuck = 0;
        for(int i = 1; i <= N; i++) 
            a[i].bg = read(), a[i].step = read(), a[i].life = read(),
            fuck = max(fuck, a[i].bg);
        sort(a + 1, a + N + 1);
        for(int i = fuck; i <= 1e6; i++)//一定要从最大值开始,,好坑。。 
            if(check(i))
                {printf("%d
    ", i); exit(0);}
    }
  • 相关阅读:
    养成好习惯:在控制面板里停止服务
    很吊炸天的Xcode插件,你想要的这都有
    Cscope how to support java and c++
    java_lambda表达式
    【C语言】14-返回指针的函数与指向函数的指针
    李洪强
    【C语言】13-指针和字符串
    李洪强-C语言7-C语言运算符
    【C语言】12-指向一维数组元素的指针
    李洪强-C语言6-控制结构
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9200840.html
Copyright © 2020-2023  润新知