cyyz : Day 1 数论整理

声明:感谢修改这篇博客的dsr

Day 1

先说一下上午的听课吧,哎~,简直了,简直(⊙o⊙)…咋说呢,引人入胜???No! 是昏昏欲睡好吧。。。一点听课欲都没有(强撑....),一上午停下来简直怀疑人生。下午上机,啥??上机居然断网!!!搞啥子嘛,,,于是整理上午的笔记,╮(╯▽╰)╭内心崩溃。

 

一、同余

知识点:

同余,如果a和b对m取模得到的结果相同,那么说a和b在模m意义下相等,或者说二者同余,记作a≡b (mod m)(其实中间应该是三条杠,但是打不出来),并且就划分为同一类。显然模m意义下一共有m类数字,以0,1,...,m-1为代表元素。注意负数也是可以取模的,例如-1 mod 3 = 2。如果a=km+r(0<=r<m),那么a=r(mod m),这称作”带余除法”。特殊的,如果r=0,那么m是a的因数,a是m的倍数,称为m整除a,记作m|a。

 

代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 ll a,b,x,y,z;
 8 inline ll read() {
 9     ll n=0,f=1;char ch=getchar();
10     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
11     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
12     return n*f;
13 }
14 inline void gcd(ll a,ll b) {
15     if(!b) {
16         x=1,y=0;
17         return ;
18     }
19     gcd(b,a%b);
20     z=x,x=y;
21     y=z-a/b*y;    
22 }
23 int main() {
24     a=read(),b=read();
25     gcd(a,b);
26     printf("%lld\n",(x+b)%b);
27     return 0;
28 }
代码实现

 

二、因数

知识点:

刚才说了,如果a|b,也就是a整除b,那么b是a的倍数,a是b的因数。显然如果a|b,a|c,那么a|(b±c),a|(bx+cy),即a整除b和c的线性组合最大公因数gcd(a,b),或者简写成(a,b),定义为,最大的d,满足d|a且d|b。显然d|(a,b)等价于,d|a且d|b另一个很显然的是,(a,b)=(a+b,b)=(a-b,b)=(a mod b,b)特别的,如果(a,b)=1,那么称作a和b互质最小公倍数[a,b]同理。二者关系:[a,b]=ab/(a,b),注意只对两个数字恒有效。

 

三、欧拉定理

 

四、逆元

 

Exgcd 求逆元 代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 typedef long long ll;
 6 ll a,b,x,y,z,n,mod;
 7 inline ll read() {
 8     ll n=0,f=1;char ch=getchar();
 9     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
10     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
11     return n*f;
12 }
13 inline void exgcd(ll a,ll b,ll &x,ll &y) {
14     if(!b) {
15         x=1,y=0;
16         return ;
17     }
18     exgcd(b,a%b,x,y);
19     z=x,x=y;
20     y=z-a/b*y;    
21 }
22 int main() {
23     n=read(),mod=read();
24     exgcd(n,mod,x,y);
25     x=(x%mod+mod)%mod;
26     printf("%lld\n",x);
27     return 0;
28 }
代码实现

 

线性求逆元 代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N=3e6+10;
 8 inline int read() {
 9     int n=0,f=1;char ch=getchar();
10     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
11     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
12     return n*f;
13 }
14 int n,p,a[N];
15 int main(){
16     n=read(),p=read();
17        a[0]=a[1]=1;
18     for(int i=2;i<=n;++i) a[i]=a[i]-(ll)(p/i)*a[p%i]%p;
19     for(int i=1;i<=n;++i) {
20         if(a[i]<0) a[i]+=p;
21         printf("%d\n",a[i]);   
22     }
23     return 0;
24 }
代码实现

 

五、扩展欧拉定理

 

 

六、卢卡斯定理

 

 

代码实现

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long ll;
 8 const int N=1e5+10;
 9 int n,m,p,k;
10 ll a[N],b[N];
11 inline int read() {
12     int n=0,f=1;char ch=getchar();
13     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
14     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
15     return n*f;
16 }
17 inline ll lucas(int x,int y) {
18     if(x<y) return 0;
19     else if(x<p) return b[x]*a[y]*a[x-y]%p;
20     else return lucas(x/p,y/p)*lucas(x%p,y%p)%p;
21 }
22 int main() {
23     k=read();
24     while (k--) {
25         n=read(),m=read(),p=read();
26         a[0]=a[1]=b[0]=b[1]=1;
27         for(int i=2;i<=n+m;++i) b[i]=b[i-1]*i%p;
28         for(int i=2;i<=n+m;++i) a[i]=(p-p/i)*a[p%i]%p;
29         for(int i=2;i<=n+m;++i) a[i]=a[i-1]*a[i]%p;
30         printf("%lld\n",lucas(n+m,m)); 
31     }
32     return 0;
33 } 
代码实现

 

七、GCD/EXGCD

代码实现:

1 inline void exgcd(ll a,ll b,ll &x,ll &y) {
2     if(!b) {
3         x=1,y=0;
4         return ;
5     }
6     exgcd(b,a%b,x,y);
7     z=x,x=y;
8     y=z-a/b*y;    
9 }
主要代码

青蛙的约会:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N=100000010;
 8 ll x,y,m,n,l,a,b,js,mod;
 9 
10 inline ll read() {
11     ll n=0,f=1;char ch=getchar();
12     while (ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
13     while (ch>='0'&&ch<='9') {n=n*10+ch-'0';ch=getchar();}
14     return n*f;
15 }
16 
17 inline ll gcd(ll a,ll b) {
18     if(b) return gcd(b,a%b);
19     else return a;
20 }
21 
22 inline void IU(ll a,ll b,ll &x,ll &y) {
23     if(!b) { 
24         x=1,y=0;
25         return ;
26     }
27     IU(b,a%b,y,x);
28     y-=a/b*x;
29 }
30 
31 inline void pd() {
32     if((b-a)%js) printf("Impossible\n");
33     else {
34         x=(x*((b-a)/js)%mod+mod)%mod;    
35         printf("%lld\n",x);    
36     }
37 }
38 
39 int main() {
40     a=read(),b=read(),m=read(),n=read(),l=read();
41     js=gcd(m-n,l);
42     mod=abs(l/js);
43     IU(m-n,l,x,y);
44     pd();
45     return 0;
46 }
代码实现

 

八、关于二元一次不定方程

知识点(Zz..摘自度娘):

使二元一次方程两边相等的一组未知数的值,叫做二元一次方程的一个解.

对二元一次方程的解的理解应注意以下几点:

①一般地,一个二元一次方程的解有无数个,且每一个解都是指一对数值,而不是指单独的一个未知数的值;

②二元一次方程的一个解是指使方程左右两边相等的一对未知数的值;反过来,如果一组数值能使二元一次方程左右两边相等,那么这一组数值就是方程的解;

③在求二元一次方程的解时,通常的做法是用一个未知数把另一个未知数表示出来,然后给定这个未知数一个值,相应地得到另一个未知数的值,这样可求得二元一次方程的一个解.

折叠注意点:

(1)二元一次方程组:由两个二元一次方程所组成的一组方程,叫做二元一次方程组.

(2)二元一次方程组的解:二元一次方程组中两个方程的公共解,叫做二元一次方程组的解.

对二元一次方程组的理解应注意:

①方程组各方程中,相同的字母必须代表同一数量,否则不能将两个方程合在一起.

②怎样检验一组数值是不是某个二元一次方程组的解,常用的方法如下:将这组数值分别代入方程组中的每个方程,只有当这组数值满足其中的所有方程时,才能说这组数值是此方程组的解,否则,如果这组数值不满足其中任一个方程,那么它就不是此方程组的解.

 

九、CRT

知识点:

定理1:几个数相加,如果存在一个加数,不能被整数a整除,那么它们的和,就不能被整数a整除。

定理2:两数不能整除,若除数扩大(或缩小)了几倍,而被除数不变,则其商和余数也同时扩大(或缩小)相同的倍数(余数必小于除数)。

 

代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 ll m[15],a[15];
 8 int n;
 9 inline ll read() {
10     ll n=0,f=1;char ch=getchar();
11     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
12     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
13     return n*f;
14 }
15 inline int fread() {
16     int n=0,f=1;char ch=getchar();
17     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
18     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
19     return n*f;
20 }
21 inline void gcd(ll a,ll b,ll &d,ll &x,ll &y) {
22     if(!b){
23         d=a;
24         x=1,y=0;
25     } else{
26         gcd(b,a%b,d,y,x);
27         y-=(a/b)*x;
28     }
29 }
30 inline ll work_(int n,ll *m,ll *a) {
31     ll p=1,d,y,x=0;
32     for(int i=0;i<n;++i) p*=m[i];
33     for(int i=0;i<n;++i){
34         ll w=p/m[i];
35         gcd(m[i],w,d,d,y);
36         x=(x+y*w*a[i])%p;
37     }
38     return (x+p)%p;
39 }
40 int main() {
41     n=fread();
42     for(int i=0;i<n;++i) m[i]=read(),a[i]=read();
43     printf("%lld",work_(n,m,a));
44 }
代码实现

 

十、扩展欧几里得

 

 

十一、线性筛

知识点:

可以在O(n)时间内筛出1~n的所有质数。如果F(n)是个积性函数,根据定义我们只要能够低于O(lgn)的知道每个F(p^c)的值,我们就能在O(n)时间内求出F(1)~F(n)。具体做法是这样的,每次枚举一个数字i,枚举所有已经筛出来的1~i中的质数k,那么x=ik不是质数,并且k是x的最小质因子。如果i%k==0,就break掉k的循环。可以证明每个数字都只会被其最小的质因子筛去,同时利用这个性质可以顺便筛出一些积性函数。这样你可以维护每个数字的最小质因子lp[n],最小质因子对应的那个若干次方lpc[n],这样对于积性函数每次只要计算满足lpc[n]=n的那些F[n],然后用积性函数的性质就可以维护1~n的F。

代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=10000010;
 6 int n,m,x;
 7 bool vis[N]={1,1};
 8 int a[N];
 9 inline int read() {
10     int n=0,f=1;char ch=getchar();
11     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
12     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
13     return n*f;
14 }
15 // 1
16 inline void ss(int n,int m) {
17     for(int i=2;i*i<=n;++i) 
18         if(!vis[i]) 
19             for(int j=i*i;j<=n;j+=i) vis[j]=true;
20     while(m--) {
21         x=read();
22         if(vis[x]) printf("No\n");
23         else printf("Yes\n");
24     }
25     return;
26 }
27 // 2 
28 inline void IU(int n,int m) {
29     int js=0;
30     for(int i=2;i<=n;++i) {
31         if(!vis[i]) a[++js]=i;
32         for(int j=1;j<=js&&i*a[j]<=n;++j) {
33             vis[i*a[j]]=true;
34             if(i%a[j]==0) break;
35         } 
36     }
37     while(m--) {
38         x=read();
39         if(vis[x]) printf("No\n");
40         else printf("Yes\n");
41     }
42 } 
43 int main() {
44     n=read(),m=read();
45     //ss(n,m);
46     IU(n,m);    
47     return 0;
48 } 
代码实现

 

 

十二、BSGS

知识点:

bsgs算法,又称大小步算法(某大神称拔山盖世算法)或北上广深算法。

主要用来解决   A^x=B(mod C)(C是质数),都是整数,已知ABCx

 

代码实现(poj 2417):

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<map>
 6 using namespace std;
 7 typedef long long ll;
 8 map<ll,int> q;
 9 ll p,m,n,a,b,z,ans,t,bz;
10 inline ll fpow(ll x) {
11     ll s=1,res=a;
12     while (x>0) {
13         if(x&1) s=(s*res)%p;
14         x=x>>1;
15         res=(res*res)%p;
16      }
17      return s;
18 }
19 int main() {
20     while (scanf("%lld%lld%lld",&p,&a,&b)!=EOF) {
21         if(a%p==0) {
22             printf("no solution\n");
23             continue;
24         }
25         q.clear();
26         m=ceil(sqrt(p));
27         bz=0,z=b%p,q[z]=0;
28         for(int i=1;i<=m;++i) z=(z*a)%p,q[z]=i;
29         t=fpow(m);
30         z=1;
31         for(int i=1;i<=m;++i) {
32             z=(z*t)%p;
33             if(q[z]) {
34                 bz=1;
35                 ans=i*m-q[z];
36                 printf("%lld\n",(ans%p+p)%p);
37                 break;
38             }
39         }
40         if(!bz) printf("no solution\n");    
41     }
42     return 0;
43 }
代码实现

 

十三、莫比乌斯反演

知识点:(摘自度娘~~

数论函数,就是正整数映射到非负整数的函数。积性函数,如果一个数论函数f满足对于任意(x,y)=1,有f(xy)=f(x)f(y),那么称f是积性函数。显只要知道了所有的f(p^c)就可以知道所有的f(n)完全积性函数,如果一个数论函数满足对于任意xy,都有f(xy)=f(x)f(y),那么称f是完全积性函数

性质:

  性质一(莫比乌斯反演公式): 

 

  性质二:μ(n)积性函数

  性质三:设f是算术函数,它的和函数 

       是积性函数,那么 也是积性函数。

 

 莫比乌斯反演定理:

设f(n) 和g(n) 是定义在正整数集合上的两个函数,定义如下。

       

      

  

证明:(摘自度娘~

充分性证明:

         

        

        

         

考虑到:

       

因此

        

 

必要性证明:

        

 

考虑到:

           

因此
        

证明2

 

 

 

 

例题:

问题描述

给定5个整数:a, b, c, d, k,你要在a中找到x。在c b,y…即GCD(x, y) = k, GCD(x, y)表示xy的最大公约数,由于选项的数量可能很大,所以只需要输出不同的数对的总数。请注意,(x=5, y=7)(x=7, y=5)被认为是相同的。

 

输入

输入由几个测试用例组成。输入的第一行是案例的数量。不超过3000例。

每一种情况包含五个整数:abcdk0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000,如上所述。

 

输出

对于每个测试用例,打印选项的数量。使用示例中的格式。

 

样例输入

2

1 3 1 5 1

1 11014 1 14409 9

 

样例输出

案例1:9

案例2:736427

 

代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<map>
 6 using namespace std;
 7 typedef long long ll;
 8 const int N=1e5+10;
 9 int v[N],a[N],b[N];
10 int n,m,js,jc,x,y,z,k;
11 ll res,ans;
12 inline int read() {
13     int n=0,f=1;char ch=getchar();
14     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
15     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
16     return n*f;
17 }
18 int main() {
19     b[1]=1;
20     for(int i=2;i<=100000;++i) {
21         if(!v[i]) a[++js]=i,b[i]=-1;
22         for(int j=1;j<=js;++j) {
23             int k=a[j]*i;
24             if(k>100000) break;
25             v[k]=1;
26             if(i%a[j]==0) { 
27                 b[k]=0;
28                 break;
29             } else b[k]=-b[i]; 
30         }
31     }
32     k=read();
33     while(k--) {
34         ++jc;
35         res=ans=0;
36         n=read(),m=read(),x=read(),y=read(),z=read();
37         if(!z) { 
38             printf("Case %d: 0\n",jc);
39             continue;
40         }
41         m/=z;y/=z;
42         if(m>y) swap(m,y);
43         for(int i=1;i<=m;++i) res+=(ll)b[i]*(m/i)*(y/i);
44         for(int i=1;i<=m;++i) ans+=(ll)b[i]*(m/i)*(m/i);
45         printf("Case %d: %lld\n",jc,res-ans/2);
46     }
47     return 0;
48 }
代码实现

 

十四、狄利克雷卷积

十五、数论分块

 

转载于:https://www.cnblogs.com/Darkpurple/p/9415866.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值