【线性模方程】BZOJ 1407 [Noi2002]Savage 题解

题目大意

n n 个人在m个点的环上,每个人初始在点 ci c i ,能活 Li L i 秒,每秒会向后走 pi p i 步,求出最小的 m m 使得任意两个人在有生之年都不会在一个点上相遇。

解题分析

转化一下这题,如果两个人i,j在第 x x 天相遇了,说明什么?

ci+xpicj+xpj(Mod m)

转移

(pipj)xcicj(Mod m) ( p i − p j ) x ≡ c i − c j ( M o d   m )

就是线性模方程,如果算出x无解(这辈子都碰不上)或 x>min(Li,Lj) x > m i n ( L i , L j ) ,则 i,j i , j 一定碰不到,这样可以先找出一个m,再用 n2 n 2 个方程来验证,但是这不满足二分,所以……穷举大法好( ans<=106 a n s <= 10 6

示例程序

(传送门)

#include<cstdio>
#define LL long long
using namespace std;
int n;
LL a[20],b[20],c[20],s,ans;
inline void readL(LL &x){
    x=0; char ch=getchar();
    while ('0'>ch||ch>'9') ch=getchar();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void exgcd(LL a,LL b,LL &d,LL &x,LL &y){
    if (!b) {d=a; x=1; y=0;}
    else {exgcd(b,a%b,d,y,x); y-=x*(a/b);}
}
bool _check(LL tem){
    for (int i=1;i<n;i++)
        for (int j=i+1;j<=n;j++){
            LL C=((a[i]-a[j])%tem+tem)%tem,A=((b[j]-b[i])%tem+tem)%tem,g,x,y;
            exgcd(A,tem,g,x,y);
            if (C%g) continue;
            int m=tem/g,k=(x*C/g%m+m)%m;
            if (k<=c[i]&&k<=c[j]) return false;
        }
    return true;
}
int main()
{
    freopen("savage.in","r",stdin);
    freopen("savage.out","w",stdout);
    scanf("%d",&n); s=0;
    for (int i=1;i<=n;i++){
        readL(a[i]); readL(b[i]); readL(c[i]); s=(s<a[i])?a[i]:s;
    }
    for (ans=s;;ans++) if (_check(ans)) {printf("%d",ans); break;}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值