先记录一下一些概念和定理

同余:给定整数a,b,c,若用c不停的去除a和b最终所得余数一样,则称a和b对模c同余,记做a≡b (mod c),同余满足自反性,对称性,传递性

定理1:

若a≡b (mod c),对某个整数k有

a+k≡b+k (mod c)

a-k≡b-k (mod c) 

ak≡bk (mod c) 

定理2:

若a≡b (mod c),d≡e (mod c),有

ax+dy≡bx+ey (mod c) ,x,y为任意整数,即同余式可以相加

ad≡be (mod c) ,即同余式可以相乘

an≡bn (mod c),n>0

f(a)≡f(b) (mod c) f(x)为任一整系数多项式

定理3:

若a≡b (mod c),且d|c 则a≡b (mod d)

若a≡b (mod c),则gcd(a,c)=gcd(b,c)

a≡b (mod ci)(1<=i<=n) 同时成立 当且仅当a若a≡b (mod lcm(c1,c2,c3...cn))

若ad≡bd (mod c)且gcd(d,c)=e 则a≡b (mod c/e)

然后就是一元线性同余方程了,也就是形如 axΞb (mod c) 这样的方程

那么上面的方程可以写作ax+cy=b的二元一次方程,那很明显这个就可以用扩展欧几里得来解决。

设g=gcd(a,c),若b%g!=0则方程无解,否则a0=a/g,b0=b/g,c0=c/g,此时gcd(a0,c0)=1,

a0x+c0y=b0就可以用扩展欧几里得解出x,然后通解就是x+kb0

至于扩展欧几里得就不多重复了,直接挂两个博客

Yo!Hadilo!欧几里得算法与扩展欧几里得算法_C++

镜外之主ACM数论之旅4---扩展欧几里德算法(欧几里德(・∀・)?是谁?)

然后就是一元线性方程组了,也就是一组一元线性方程组

x≡b1(mod c1)

x≡b2(mod c2)

x≡b3(mod c3)

....

x≡bn(mod cn)

那么我们就由前三组来看,

x=k1*c1+b1,x=k2*c2+b2,x=k3*c3+b3 ,k1,k2,k3都为任意整数。

前两个式子联立得,k1*c1+b1=k2*c2+b2,整理可得k2*c2-k1*c1=b1-b2,

此时扩展欧几里得可以解出一个最小非负整数解k2",或者直接无解了。

那么x有一个解为x2=k2"*c2+b2,而k2的通解为k2=k2"+m*c1/gcd(c1,c2), m为任意整数。

再引入第三个式子,就有k3*c3+b3=k2*c2+b2。

代入k2 也就是k3*c3+b3=k2"*c2+m*c1*c2/gcd(c1,c2)+b2,再代入x2整理就得,

k3*c3-m*c1*c2/gcd(c1,c2)=x2-b3,这时解出k3",就有x3,和k3通解

那么以此类推,联立后面的方程,最终解出的xn就是最终结果了。

Strange Way to Express Integers POJ - 2891

 #include<cstdio>
typedef long long ll;
const int N=1e5+;
ll bb[N],cc[N];
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=;
y=;
return a;
}
ll g=exgcd(b,a%b,y,x);
y-=a/b*x;
return g;
}
ll linemod(int n){
ll a,b,c,ans=bb[],cp=cc[],x,y,g;
for(int i=;i<n;i++){
a=cc[i];c=cp;b=ans-bb[i];
g=exgcd(a,c,x,y);
if(b%g) return -;
a/=g;b/=g;c/=g;
x=(x*b%c+c)%c;
ans=x*cc[i]+bb[i];
cp*=a;
ans=(ans%cp+cp)%cp;
}
return ans;
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<n;i++) scanf("%lld%lld",&cc[i],&bb[i]);
printf("%lld\n",linemod(n));
}
return ;
}

板子咯

还有几题 HDU1021 HDU 1573 HDU3579都可以练一练手,HDU国庆进不去,嘤嘤嘤。

然后多元线性同余方程的话就简单把书上的抄一下。

定义:形如a1x2+a2x2+a3x3+...+anxn+b≡0(mod c) 的同余方程成为多元线性同余方程。

性质:多元线性同余方程。a1x2+a2x2+a3x3+...+anxn+b≡0(mod c) 有解的充分必要条件是gcd(a1,a2,a3,...an,c) | b,若有解,解的个数为cn-1*gcd(a1,a2,a3...,an,c)

解法:令d=gcd(a1,a2,a3,...an,c) ,d1=gcd(a1,a2,a3,...an-1,c),那么gcd(d1,an)=d,由方程可知anxn+b≡0 (mod d1) 

这样那方程分成了a1x2+a2x2+a3x3+...+an-1xn-1+b1d1≡0(mod c) (b1d1=anxn+b) 和anxn+b≡0 (mod d1)两个方程,两个都满足时即可一步步解出x

这个没啥题,就当扩展知识,了解一下。

然后是高次同余方程,我的书里说,高次同余方程比较复杂,所以本书仅讨论ax≡b(mod c) (0<=x<C)的问题

然后解决的方法是拔山盖世BSGS算法,全称是Baby Step Giant Step,小步大步算法,因为整个算法取决于一个分块的思想。

先放几个博客,因为在构造方式上的不同,所以在实现方法上有着要不要通过扩展欧几里得算法来求逆元的差异,我比较懒,就没有。

首先我们先来对于c是质数来进行讨论,c是质数的话,那么由费马小定理就有aphi(c)≡1(mod c),那么ax≡b(mod c) 有解的话,x肯定是在0~phi(c) phi(c)是c的欧拉函数哦

那么我们可以设x=i*n-j,n为√c,0<=j<n那么就有ai*n-j≡b(mod c) ,也就是ai*n≡b*aj(mod c),(设x=i*n+j的话,就得用扩展欧几里得求逆元了)

上面就是分块的思想,每个an为一块,这样我们先枚举j,将b*aj预处理保存在哈希表中,然后在枚举i,看相应的ai*n在哈希表有没有存在,存在的话,就可以得到一组(i,j),

代入x=i*n-j,即可得出x,总的时间复杂度就√c

而如果c不是质数,也是a和c不互质的话,那么此时就是想办法使得gcd(a,c)=1,这个在上面的扩展BSGS里详细的证明了,这里不重复了。

Discrete Logging POJ - 2417

Clever YPOJ - 3243

Mod Tree HDU - 2815

上面是三个板子题,可以练练手。

 #include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf=1e9+;
struct Hashmap{
static const int Hash=,N=;
int num,head[Hash],a[N+],b[N+],ne[N+];
int top,sta[N+];
void clear(){
num=;
while(top) head[sta[top--]]=;
}
void add(int x,int y){
a[++num]=y;
ne[num]=head[x];
b[num]=inf;
head[x]=num;
}
bool count(int y){
int x=y%Hash;
for(int j=head[x];j;j=ne[j])
if(y==a[j]) return true;
return false;
}
int &operator [](int y){
int x=y%Hash;
for(int j=head[x];j;j=ne[j])
if(y==a[j]) return b[j];
add(x,y);
sta[++top]=x;
return b[num];
}
}mmp;
ll bsgs(ll a,ll b,ll c){
if(c==) return !b ? !a : -;
if(a%c==) return !b ? : -;
if(b==) return ;
int sqc=ceil(sqrt(1.0*c));
ll aa=,ac=,ab;
mmp.clear();
for(int i=;i<sqc;i++){
ab=aa*b;
if(ab>=c) ab%=c;
mmp[ab]=i;
aa*=a;
if(aa>=c) aa%=c;
}
for(int i=;i<=sqc;i++){
ac*=aa;
if(ac>=c) ac%=c;
if(mmp.count(ac)) return i*sqc-mmp[ac];
}
return -;
}
int main(){
ll x,y,z,ans;
while(~scanf("%lld%lld%lld",&z,&x,&y)){
ans=bsgs(x,y,z);
if(ans==-) printf("no solution\n");
else printf("%lld\n",ans);
}
return ;
}

c为质数

 #include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf=1e9+;
struct Hashmap{
static const int Hash=,N=1e5+;
int num,head[Hash],a[N+],b[N+],ne[N+];
int top,sta[N+];
void clear(){
num=;
while(top) head[sta[top--]]=;
}
void add(int x,int y){
a[++num]=y;
ne[num]=head[x];
b[num]=inf;
head[x]=num;
}
bool count(int y){
int x=y%Hash;
for(int j=head[x];j;j=ne[j])
if(y==a[j]) return true;
return false;
}
int &operator [](int y){
int x=y%Hash;
for(int j=head[x];j;j=ne[j])
if(y==a[j]) return b[j];
add(x,y);
sta[++top]=x;
return b[num];
}
}mmp;
//map<ll,int> mmp;
ll gcd(ll a,ll b){
return !b ? a : gcd(b,a%b);
}
ll bsgs(ll a,ll b,ll c){
if(b>=c) return -;
if(c==) return !b ? !a : -;
if(a%c==) return !b ? : -;
if(b==) return ;
int sqc,d=;
ll aa=,ac=,ab,g;
while((g=gcd(a,c))!=){
if(b%g) return -;
b/=g;c/=g;
ac*=a/g;
if(ac>=c) ac%=c;
d++;
if(ac==b) return d;
}
mmp.clear();
sqc=ceil(sqrt(1.0*c));
for(int i=;i<sqc;i++){
ab=aa*b;
if(ab>=c) ab%=c;
mmp[ab]=i;
aa*=a;
if(aa>=c) aa%=c;
}
for(int i=;i<=sqc;i++){
ac*=aa;
if(ac>=c) ac%=c;
if(mmp.count(ac)) return sqc*i-mmp[ac]+d;
}
return -;
}
int main(){
ll x,y,z,ans;
while(~scanf("%lld%lld%lld",&x,&z,&y)){
ans=bsgs(x,y,z);
if(ans==-) printf("Orz,I can’t find D!\n");
else printf("%lld\n",ans);
}
return ;
}

c不是质数

最后就是中国剩余定理了。直接上两博客吧。

镜外之主ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)

niiick中国剩余定理 && 扩展中国剩余定理

并不是很难的东西,原理跟多元线性同余方程类似扩展中国剩余定理更是同一个东西,只不过推导的过程有些不一样。这里便不重复。

BiorhythmsPOJ - 1006

P3868 [TJOI2009]猜数字

P4777 【模板】扩展中国剩余定理(EXCRT)

Strange Way to Express Integers POJ - 2891

#include<cstdio>
typedef long long ll;
ll bb[],cc[]={,,},cp;
ll exgcd(ll a,ll b, ll &x,ll &y){
if(!b){
x=;
y=;
return a;
}
ll g=exgcd(b,a%b,y,x);
y-=a/b*x;
return g;
}
ll inv(ll a,ll c){
ll g,x,y;
g=exgcd(a,c,x,y);
return g== ? (x%c+c)%c : -;
}
ll crt(int n){
ll ans=,temp;
cp=;
for(int i=;i<n;i++) cp*=cc[i];
for(int i=;i<n;i++){
temp=cp/cc[i];
ans+=bb[i]*temp*inv(temp,cc[i]);
if(ans>=cp) ans%=cp;
}
return (ans+cp)%cp;
}
int main(){
int t=;
ll d,ans;
while(~scanf("%lld%lld%lld%lld",&bb[],&bb[],&bb[],&d)){
if(bb[]==-&&bb[]==-&&bb[]==-) break;
ans=crt()-d;
if(ans<=) ans+=cp;
printf("Case %d: the next triple peak occurs in %lld days.\n",t++,ans);
}
return ;
}

crt

 #include<cstdio>
typedef long long ll;
const int N=1e5+;
ll bb[N],cc[N];
ll exgcd(ll a,ll b, ll &x,ll &y){
if(!b){
x=;
y=;
return a;
}
ll g=exgcd(b,a%b,y,x);
y-=a/b*x;
return g;
}
ll excrt(int n){
ll ans=,cp=,a,b,c,g,x,y;
for(int i=;i<n;i++){
a=cp,c=cc[i],b=bb[i]-ans;
g=exgcd(a,c,x,y);
if(b%g) return -;
b/=g;c/=g;
x=(x*b%c+c)%c;
ans+=x*cp;
cp*=c;
ans=(ans%cp+cp)%cp;
}
return ans;
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<n;i++) scanf("%lld%lld",&cc[i],&bb[i]);
printf("%lld\n",excrt(n));
}
return ;
}

excrt

数论之同余性质 线性同余方程&拔山盖世BSGS&中国剩余定理的更多相关文章

  1. acm数论之旅--中国剩余定理

    ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)   中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ...

  2. 洛谷P2480 [SDOI2010]古代猪文(费马小定理,卢卡斯定理,中国剩余定理,线性筛)

    洛谷题目传送门 蒟蒻惊叹于一道小小的数论题竟能涉及这么多知识点!不过,掌握了这些知识点,拿下这道题也并非难事. 题意一行就能写下来: 给定\(N,G\),求\(G^{\sum \limits _{d| ...

  3. 初等数论-Base-2(扩展欧几里得算法,同余,线性同余方程,(附:裴蜀定理的证明))

    我们接着上面的欧几里得算法说 扩展欧几里得算法 扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式\(^①\): ax+by = gcd(a, b) =d(解一定存在,根据数论中的 ...

  4. [TCO 2012 Round 3A Level3] CowsMooing (数论,中国剩余定理,同余方程)

    题目:http://community.topcoder.com/stat?c=problem_statement&pm=12083 这道题还是挺耐想的(至少对我来说是这样).开始时我只会60 ...

  5. 【数论】不定方程&逆元&中国剩余定理

    一.不定方程 要求逆元,首先要知道什么是不定方程. 已知a,b,c,求解x,y,形如ax + by = c 的方程就是不定方程. 不定方程有两种解的情况: 1.无解 2.存在且有无限的解 那么,如何判 ...

  6. 数论E - Biorhythms(中国剩余定理,一水)

    E - Biorhythms Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Subm ...

  7. (数论)51NOD 1079 中国剩余定理

    一个正整数K,给出K Mod 一些质数的结果,求符合条件的最小的K.例如,K % 2 = 1, K % 3 = 2, K % 5 = 3.符合条件的最小的K = 23.   Input 第1行:1个数 ...

  8. AcWing 204. 表达整数的奇怪方式 (线性同余方程组)打卡

    给定2n个整数a1,a2,…,ana1,a2,…,an和m1,m2,…,mnm1,m2,…,mn,求一个最小的整数x,满足∀i∈[1,n],x≡mi(mod ai)∀i∈[1,n],x≡mi(mod  ...

  9. ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)

    中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 7个7个分剩2个 问这个物品有多少个 解这题,我们需要构造一个答案 我们需要构造这 ...

随机推荐

  1. 【AC自动机】洛谷三道模板题

    [题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...

  2. k8s之网络插件flannel及基于Calico的网络策略

    1.k8s网络通信 a.容器间通信:同一个pod内的多个容器间的通信,通过lo即可实现; b.pod之间的通信:pod ip <---> pod ip,pod和pod之间不经过任何转换即可 ...

  3. Thread 和 Runnable

    Thread 和 Runnable 1. 简介 Java 主要是通过 java.lang.Thread 类以及 java.lang.Runnable 接口实现线程机制的. Thread 类为底层操作系 ...

  4. Apache开启.htaccess 支持

    (1) <Directory "${SRVROOT}/htdocs"> # # Possible values for the Options directive ar ...

  5. WebStorm使用码云插件问题

    由于项目需求,需要在WebStorm中使用码云插件,在下载安装的过程中出现一系列的问题,现总结出现的问题和解决方法. 先说一下码云是什么?码云有什么作用? 码云的主要功能: 码云除了提供最基础的 Gi ...

  6. Java基础加强-日志

    /*日志*/ 从功能上来说,日志API本身所需求的功能非常简单,只需要能够记录一段文本即可 API的使用者在需要记录时,根据当前的上下文信息构造出相应的文本信息,调用API完成记录.一般来说,日志AP ...

  7. Delphi 10.3.3最新消息

    有朋友说,已经开始内测,预计10月末发版,按最新的路线图,此版本支持iOS 13及Android 64位. 2019-11-18,今天,下载及注册机都来了,快下载安装,试用吧. 需要的话加入QQ群20 ...

  8. 【Java并发】线程安全和内存模型

    一.概述 1.1 什么是线程安全? 1.2 案例 1.3 线程安全解决办法: 二.synchronized 2.1 概述 2.2 同步代码块 2.3 同步方法 2.4 静态同步函数 2.5 总结 三. ...

  9. Centos7安装dig命令

    作者: jwj 时间: 2018-10-17 分类: 服务器 最近做一个项目,需要用到Gmail邮箱发送邮件,但发现发送不出去.排查问题时,需要用到dig命令,但使用时,却提醒我dig命令不存在~那就 ...

  10. PAT Basic 1085 PAT单位排行 (25 分)

    每次 PAT 考试结束后,考试中心都会发布一个考生单位排行榜.本题就请你实现这个功能. 输入格式: 输入第一行给出一个正整数 N(≤),即考生人数.随后 N 行,每行按下列格式给出一个考生的信息: 准 ...