zoukankan      html  css  js  c++  java
  • BZOJ-1407 Savage 枚举+拓展欧几里得(+中国剩余定理??)

    zky学长实力ACM赛制测试,和 大新闻(YveH) 和  华莱士(hjxcpg) 组队。。。2h 10T,开始 分工我搞A,大新闻B,华莱士C,于是开搞;
    然而第一题巨鬼畜,想了40min发现似乎不可做(人傻),然而BC也在搞。。。于是开始做第四道;
    大约1h10’ B题A了。。1h30' C题也A了=  =;
    后来去搞F,公式推得很快,并且很自信是对的。。于是筛!搞!,一交 TLE?!,然后意识到 结果可以直接筛,可以省去搞得过程
    不虚,改!!然后时间到了。。。毫无贡献的傻逼一个。。。。可怕。
    

    于是搞了下第四题D:
    1407: [Noi2002]Savage
    Time Limit: 5 Sec Memory Limit: 64 MB
    Submit: 1128 Solved: 513
    [Submit][Status][Discuss]

    Description
    这里写图片描述

    Input
    第1行为一个整数N(1<=N<=15),即野人的数目。第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=106 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。

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

    Sample Input
    3
    1 3 4
    2 7 3
    3 2 1

    Sample Output
    6
    该样例对应于题目描述中的例子。

    HINT

    Source

    分析:
    此题但是想到是方程组,于是直接往中国剩余定理上想了。。事后发现其实只需要 解线性的同余方程 即可,仅仅需要拓展欧几里得。。
    枚举m,然后利用拓欧进行判定。
    首先发现规律:(loc为初始洞穴,mov为移动数,ans为相撞所需年数,m为洞穴数)
    loc【i】+mov【i】*ans=loc【j】+mov【j】*ans (mod m)
    于是移项得:
    (mov【i】-mov【j】) *ans=loc【j】-loc【i】 (mod m)
    判定即可;
    值得注意的几个小地方:
    为了取模的方便,可以把初始的洞穴序号-1;
    题目并不符合二分的性质,当然数据范围,枚举绝对可行;
    转成不定方程后,mov【i】-mov【j】与m未必互质,所以应该先同除一个gcd;
    最后,如果有解,且解<=lif【i】、lif【j】(寿命年份)即不可行;
    (偶对,似乎网上有用中国剩余定理解得。。然而我当时并不能想出来,人傻╮(╯▽╰)╭)

    坑了我自己的一个地方。。
    这里写图片描述
    这破地方开始没注意于是坑了近10分钟。。
    这里写图片描述

    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n;
    int loc[20],mov[20],lif[20];
    int st=0;
    
    int x,y;int gcd;
    void exgcd(int a,int b,int &x,int &y,int &gcd)
    {
        if (b==0) {gcd=a; x=1; y=0; return;}
        exgcd(b,a%b,y,x,gcd);
        y-=a/b*x;
    }
    
    bool check(int m)
    {
        for (int i=1; i<=n-1; i++)
            for (int j=i+1; j<=n; j++)
                {
                    int dloc=((loc[j]-loc[i])%m+m)%m;
                    int dmov=((mov[i]-mov[j])%m+m)%m;
                    exgcd(dmov,m,x,y,gcd);
                    if ((dloc%gcd)!=0)  continue;
                    dloc/=gcd;
                    int mm=m/gcd;int ans=(dloc*x%mm+mm)%mm;
                    if (ans<=lif[i] && ans<=lif[j]) return false;           
                }
        return true;
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1; i<=n; i++)
            {
                scanf("%d%d%d",&loc[i],&mov[i],&lif[i]);
                st=max(st,loc[i]);loc[i]--;
            }
        for (int i=st;;i++)
            if (check(i))  {printf("%d
    ",i);break;}
        return 0;
    }
  • 相关阅读:
    Computer Browser服务自动停止
    Group By中Case分类统计
    C#判断网络状态
    Win7中VC6打开文件报错(转)
    SqlBulkCopy(大数据量拷贝)
    vc6开发ActiveX并发布全攻略(二)(转)
    VC6 Activex控件调试
    VC MessageBox
    常用基本AT指令
    WinForm自动重启
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346202.html
Copyright © 2011-2022 走看看