中国剩余定理(孙子定理):
孙子定理是中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国余数定理。
————参见百度;
中国剩余定理给出了以下的一元线性同余方程组
有解的判定条件,并用构造法给出了在有解情况下解的具体形式。
好吧前面都没啥用。。。。。。
例:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
解法:三人同行七十稀,五树梅花廿一支,七子团圆正半月,除百零五使得知。
解释:
题目:有一堆东西不知道有多少,设为 N,现在有三个条件:
N%3=2; N%5=3; N%7=2;
解答: 定义 lcm———“公倍数”。(非最小)
1. lcm(5,7)%3==1 lcm(5,7)=70;
2. lcm(3,5)%7==1 lcm(3,5)=15;
3. lcm(3,7)%5==1 lcm(3,7)=21;
而 N=70*2+15*3+21*2 ;
而3,5,7的最小公倍数为 105
最小解:N=(N+105)%105, N=0时N+=105;
那么对于BiorhythmsHDU - 1370 题,具体解法为:
(N+d)%23==p; (N%d)%28==e;(N+d)%33==I;
1. lcm(23,28)%33==1 lcm()=1288;
2. lcm(23,33)%28==1 lcm()=14421;
3. lcm(28,33)%23==1 lcm()=5544;
MOD=gcd(23,28,33);
N=(1288*p+14421*e+5544*I-d+MOD)%MOD;S同样当N=0时,N+=MOD;
代码:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int kase=1;
int p,e,i,d;
while(scanf("%d%d%d%d",&p,&e,&i,&d))
{
if(p==-1&&e==-1&&i==-1&&d==-1)
break;
int MOD=21252;
int n=(5544*p+14421*e+1288*i-d+MOD)%MOD;
if(n==0)
n=MOD;
cout<<"Case "<<kase++<<": the next triple peak occurs in "<<n<<" days."<<endl;
}
if(T)
cout<<endl;
}
return 0;
}
文末附上中国剩余定理的模板:
设正整数两两互素。
LL exgcd(LL a, LL b, LL &x, LL &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
LL d = exgcd(b,a%b,y,x);
y -= a / b *x;
return d;
}
int china(int a[],int m[],int n) // a + tm = x ,m模(两两互素),n个方程
{
int M = 1;
int ans = 0;
for(int i=1; i<=n; i++)
M *= m[i];
for(int i=1; i<=n; i++)
{
int x, y;
int Mi = M / m[i];
exgcd(Mi, m[i], x, y);
ans = (ans + Mi * x * a[i]) % M;
}
if(ans < 0) ans += M;
return ans;
}
若m不是互为素数,则需要采用两两合并的方法,
x=x1*m1+a1; x=x2*m2+a2;
x1*m1+a1=x2*m2+a2
x1*m1-x2*m2=a2-a1;————(就类似于ax+by=c)
用扩欧来解出x1的最小整数解,然后代入 x=x1*m1+a1;
然后 得到下一个同余 的式子 y%lcm(m1,m2)=x%lcm(m1,m2);
进行下一步的合并。
代码:
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(b==0)
{
d=a;
x=1;
y=0;
return ;
}
ex_gcd(b,a%b,d,y,x);
y-=a/b*x;
}
ll gcd(ll a,ll b)
{
if(!b) return a;
return gcd(b,a%b);
}
ll Chinasolve(ll n) //chushu yushu
{
ll x1,x2,d,x,y,dm;
ll c,c1,c2;
x1=a[0];c1=b[0];
for(int i=1;i<n;i++)
{
x2=a[i];
c2=b[i];
ex_gcd(x1,x2,d,x,y);
dm=x2/d;
c=c2-c1;
if(c%d) return -1;
x=((x*c/d)%dm+dm)%dm;
c1=x1*x+c1;
x1=x1*x2/d;
}
dg=x1;
if(!c1)
{
c1=1;
for(int i=0;i<n;i++)
{
c1=c1*a[i]/gcd(c1,a[i]);
}
dg=c1;
}
return c1;
}