Loading

UVA756

本题可以说是中国剩余定理模板。

简单说一下中国剩余定理,就是有方程组:

\[\begin{cases} x \equiv a_1 \pmod {b_1}\\ x \equiv a_2 \pmod {b_2}\\ x \equiv a_3 \pmod {b_3}\\ \cdots\\ x \equiv a_n \pmod {b_n} \end{cases}\]

当所有的 \(b\) 互质时,方程组存在整数解。

\(S=\prod_{i=1}^{n} {b_i}\)\(s_i=\frac{S}{b_i}\)\(t_i\) 为方程 \(s_i\times t_i\equiv 1 \pmod {b_i}\) 的任意一个解。

则方程组有一个解为

\[\sum_{i=1}^{n} a_i\times s_i\times t_i \]

并且方程组在模 \(S\) 意义下有唯一解,可以根据扩展欧几里得算法来实现。

具体证明这里不给出。

回到题目。

发现 \(28\)\(23\)\(33\) 互质,给出的式子又满足中国剩余定理的形式,就可以直接求出满足题目要求的 \(x\)

要注意求出的 \(x\) 必须满足 \(x>d\) 的条件。我的处理方法是不断加这三个数的乘积直到满足条件为止。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rr register 
#define maxn 10000100
#define INF 0x3f3f3f3f
#define Mod 1000000007
//#define int long long 

using namespace std;

const int M=23*28*33;
int a[5],d,Ans,ans,cnt;
int m[5]={0,23,28,33};

inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    return s*w;
}

int exgcd(int a,int b,int &x,int &y){
    if(!b){x=1;y=0;return a;}
    ans=exgcd(b,a%b,x,y);
    int t=x;x=y;y=t-a/b*y;
    return ans;
}

int main(){
    while(1){
        a[1]=read();a[2]=read();a[3]=read();d=read();Ans=0; 
        if(a[1]==a[2]&&a[2]==a[3]&&a[3]==d&&d==-1) return 0; 
        for(int i=1,times,x,y;i<=3;i++){
            times=M/m[i];
            exgcd(times,m[i],x,y);
            Ans=((Ans+times*a[i]*x)%M+M)%M;
        }
        while(Ans<=d) Ans+=M;
        printf("Case %d: the next triple peak occurs in %d days.\n",++cnt,Ans-d);
    }
} 
posted @ 2021-04-25 16:41  KnightL  阅读(37)  评论(0编辑  收藏  举报