P2421 [NOI2002]荒岛野人

题目链接

暴力非常好写,按题目模拟即可。这样经过测试有40分。

正解做法:

题目上的条件可以转化为找一个山洞数,使下面的式子无解。

接着移项,可以变为

 

 典型的同余方程,然后因为题目中的n极小,所以可以n^2暴力判断。

枚举的时候注意初始值为c[i]的最大值,然后枚举判断,无解的情况有两种:

1.在有生之年内都不会在一个山洞中,也就是该方程的最小正整数解>t值。

2.本来这个方程就无解。

还有,求得的gcd可能为负值,要变为相反数再求解最小正整数解。

代码(40分暴力):

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int n;
int save[maxn],c[maxn],p[maxn],t[maxn],life[maxn];
int maxx;
int tot;
bool flag;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&c[i],&p[i],&t[i]);
        maxx=max(c[i],maxx);
        life[i]=t[i];
        save[i]=c[i];
    }
    for(int i=maxx;;i++){
        flag=false;
        tot=0;
        memcpy(c,save,sizeof(c));
        memcpy(t,life,sizeof(t));
        while(1){
            for(int j=1;j<=n;j++){
                int save=c[j];
                if(t[j]>0){
                    c[j]+=p[j];    
                    if(c[j]>i) c[j]%=i;
                    if(!c[j]) c[j]=save;
                }  
            }
            for(int j=1;j<=n;j++){
                for(int k=j+1;k<=n;k++){
                    if(c[j]==c[k]&&t[j]>0&&t[k]>0){
                        flag=true;
                        break;
                    } 
                }
            }
            for(int j=1;j<=n;j++) t[j]--;
            for(int j=1;j<=n;j++) if(!t[j]) tot++;
            if(flag||tot==n) break;
         }
         if(!flag){
             printf("%d\n",i);
             return 0;
        }
    }
    return 0;
}
View Code

正解(exgcd):

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int n;
int c[maxn],p[maxn],t[maxn];
long long x,y;
int maxx;
long long exgcd(long long a,long long &x,long long b,long long &y){
    if(!b){
        x=1;
        y=0;
        return a;
    }
    long long gcd=exgcd(b,x,a%b,y);
    long long tmp=x;
    x=y;
    y=tmp-(a/b)*x;
    return gcd;
}
bool check(long long ans){
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            long long a=p[i]-p[j],b=ans,cc=c[j]-c[i];
            long long gcd=exgcd(a,x,b,y);
            if(cc%gcd) continue;
            if(b/gcd<0) b=-b;//注意有负数的情况 
            x=((x*cc/gcd)%(b/gcd)+(b/gcd))%(b/gcd);
            if(x<=t[i]&&x<=t[j]) return false;
        }
    }
    return true;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&c[i],&p[i],&t[i]);
        maxx=max(c[i],maxx);
    } 
    for(int i=maxx;;i++){
        if(check(i)){
            printf("%d\n",i);
            return 0;
        }
    } 
     return 0;
} 
View Code

 

 

 

posted @ 2019-10-17 22:01  JBLee  阅读(152)  评论(0编辑  收藏  举报