【説明する】数論
一、斐波那契数列:
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6772498.html
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 int main() 5 { 6 double a,n,ans; 7 cin>>n; 8 //n--; //(第一项是0时) 9 a=sqrt(5); 10 ans =(a/5) * (pow( (1+a)/2 ,n) - pow((1-a)/2 ,n)); 11 cout<<ans; 12 return 0; 13 }
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 using namespace std; 5 int a[10001]; 6 int main() 7 { 8 int n; 9 a[1]=1; 10 a[2]=1; 11 scanf("%d",&n); 12 for(int i=3;i<=n;i++) 13 { 14 a[i]=a[i-1]+a[i-2]; 15 } 16 cout<<a[n]; 17 return 0; 18 }
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 using namespace std; 5 int a[10001]; 6 int f(int n) 7 { 8 if(n==1||n==2)return 1; 9 else return f(n-1)+f(n-2); 10 } 11 int main() 12 { 13 int n; 14 a[1]=1; 15 a[2]=1; 16 scanf("%d",&n); 17 printf("%d",f(n)); 18 return 0; 19 }
接下来就是一些很神的东西啦!(快速幂)
1 #include<iostream> 2 #include<cstring> 3 4 using namespace std; 5 6 void multi(int a[2][2],int b[2][2],int q)//前缀 7 { 8 int c[2][2]; 9 memset(c,0,sizeof(c));//进行初始化清空,因为不只有一组数据,有t组 10 for(int i=0;i<2;i++) 11 for(int j=0;j<2;j++) 12 for(int k=0;k<2;k++) 13 c[i][j]=(c[i][j]+(a[i][k]*b[k][j])%q)%q; 14 for(int i=0;i<2;i++) 15 for(int j=0;j<2;j++) 16 a[i][j]=c[i][j]; 17 } 18 19 void fastpow(int n,int q) 20 { 21 int result[2][2]={1,0,1,0}; 22 int a[2][2]={1,1,1,0}; 23 while(n)//如果n不为0,一直做下面的循环 24 { 25 if(n&1)//表明如果它是奇数 26 multi(result,a,q); 27 multi(a,a,q); 28 n>>=1;//位运算,相当于n/2 29 } 30 int ans=result[0][1]%q; 31 cout<<ans<<endl; 32 } 33 int main () 34 { 35 int t;//给出(t)多组数据 36 int n,q;//第几项,模几 37 cin>>t; 38 while(t--) 39 { 40 cin>>n>>q; 41 n++;//因为斐波那契数列是从第0项开始的 42 fastpow(n,q);//快速幂 43 } 44 return 0; 45 }
快速幂如果不理解的话,接下来会讲到啦~
二、素数:
详细请见http://www.cnblogs.com/zxqxwnngztxx/p/6735297.html
可做洛谷3383来练手https://www.luogu.org/problem/show?pid=3383
线性筛法求素数的代码:
自我感觉1比较好用~而且会快好多!(这个顺序应该是按ms排序的吧)
#include <iostream> #include <cstdio> #include <cmath> using namespace std; const int Maxn = 10000001; int cnt,prime[Maxn]; bool notprime[Maxn]; int main() { int n,t; scanf("%d%d",&n,&t); notprime[0]=notprime[1]=true; for(int i=2; i<=n; ++i) { if(!notprime[i]) prime[++cnt]=i; for(int j=1; j<=cnt && i*prime[j]<=n; ++j) { notprime[i*prime[j]]=true; if(i%prime[j]==0) break; } } while(t--) { int i; scanf("%d",&i); if(notprime[i]) printf("No\n"); else printf("Yes\n"); } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN=10000001; int vis[MAXN]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=2;i<=sqrt(n);i++) { if(vis[i]==0) { for(int j=i*i;j<=n;j=j+i) { vis[j]=1; } } } vis[1]=1; int a; for(int i=1;i<=m;i++) { scanf("%d",&a); if(vis[a]==0) printf("Yes\n"); else printf("No\n"); } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN=10000001; int vis[MAXN]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=2;i<=sqrt(n+0.5);i++) { if(!vis[i]) { for(int j=i<<1;j<=n;j+=i) { vis[j]=1; } } } vis[1]=1; int a; for(int i=1;i<=m;i++) { scanf("%d",&a); if(vis[a]==0) printf("Yes\n"); else printf("No\n"); } return 0; }
三、(扩展)欧几里得算法(裴蜀定理):
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6741002.html
codevs有道题(同余方程)可以去做做试试:http://codevs.cn/problem/1200/
1 #include<iostream> 2 using namespace std; 3 int main() 4 { 5 int n,m,r; 6 cin>>m>>n; 7 r=m%n; 8 while(r!=0) 9 { 10 m=n; 11 n=r; 12 r=m%n; 13 } 14 cout<<n; 15 }
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 5 using namespace std; 6 7 long long exgcd(long long a,long long b,long long &x,long long &y) 8 { 9 if(b==0) 10 { 11 x=1; 12 y=0; 13 return a; 14 } 15 long long r=exgcd(b,a%b,x,y),t=x; 16 x=y;y=t-y*(a/b); 17 return r; 18 } 19 20 int main() 21 { 22 long long a1,b1,x1,y1; 23 cin>>a1>>b1; 24 exgcd(a1,b1,x1,y1); 25 while(x1<0) x1+=b1; 26 cout<<x1; 27 return 0; 28 }
四、求二元一次不定方程
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 5 using namespace std; 6 7 int x,y; 8 9 int gcd(int a,int b)//求最大公约数 10 { 11 if(b==0) 12 return a; 13 else 14 return gcd(b,a%b); 15 } 16 17 int exgcd(int a,int b,int &x,int &y)//扩展欧几里得 18 { 19 if(b==0) 20 { 21 x=1; 22 y=0; 23 return a; 24 } 25 int r=exgcd(b,a%b,x,y); 26 int temp=x; 27 x=y; 28 y=temp-(a/b)*y; 29 return r; 30 } 31 int main() 32 { 33 int a,b,c; 34 scanf("%d%d%d",&a,&b,&c); 35 int y=gcd(a,b); 36 if(c%y!=0)//判断是否有解,如果无解,输出“-1”,代表无法找到 37 { 38 printf("-1"); 39 return 0; 40 } 41 else exgcd(a,b,x,y); 42 while(x<0) 43 { 44 x=x+b; 45 y=y+b; 46 } 47 x*=c; 48 printf("%d %d",x,y); 49 return 0; 50 }
五、快速幂
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6759223.html
#include<iostream> #include<cmath> #include<cstdio> #define LL long long using namespace std; LL b,p,k; LL fastpow(LL a,LL b) { LL r=1; LL base=a; while(b!=0) { if(b%2!=0)//奇次幂 r=r*base; base=base*base; b=b/2; } return r; } LL fff(LL n,LL m) { if(m == 0) return 1; LL t = fff(n,m /2); t = 1LL * t * t % k; if(m&1) t = 1LL * t * n % k; return t; } LL mod_exp(LL a, LL b, LL c) //快速幂取余a^b%c { LL res,t; res=1%c; t=a%c; while(b) { if(b&1) { res=res*t%c; } t=t*t%c; b>>=1;//就等价于b/2(位运算) } return res; } int main() { scanf("%lld%lld%lld",&b,&p,&k); LL tmpb=b; b%=k;//防止b太大 /* start 快速幂求得b^p */ cout<<tmpb<<"^"<<p<<"="<<fastpow(b,p)<<endl; /* end 快速幂求得b^p */ /* start 快速幂求得b^p%k */ cout<<tmpb<<"^"<<p<<" mod "<<k<<"="<<mod_exp(b,p,k)<<endl; /* 方法一 end */ cout<<tmpb<<"^"<<p<<" mod "<<k<<"="<<fff(b,p)<<endl; /* 方法二 end */ /* end 快速幂求得b^p%k */ return 0; }
六、费马小定理
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6744377.html
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<ctime> 6 #define ll long long int//能够直接使用long long 7 8 using namespace std; 9 10 ll n; 11 ll pd[14]={10,35,77,535,71497,2,3,5,7,11,3161}; 12 ll fastmul(ll a,ll b) 13 { 14 ll r=0; 15 ll base=a; 16 while(b!=0) 17 { 18 if(b%2!=0) 19 { 20 b--; 21 r=(r+base)%n; 22 } 23 b=b/2; 24 base=(base+base)%n; 25 } 26 return r%n; 27 } 28 ll fastpow(ll a,ll b) 29 { 30 ll r=1; 31 ll base=a; 32 while(b!=0) 33 { 34 if(b%2!=0) 35 r=fastmul(r,base)%n; 36 base=fastmul(base,base)%n; 37 b=b/2; 38 } 39 return r%n; 40 } 41 ll check(ll n) 42 { 43 if(n==2) return 1; 44 if(n<2&&(n%2==0)) return 0; 45 for(ll i=0;i<11;i++) 46 { 47 ll x=pd[i];//进行特判 48 if(x%n==0) 49 continue;//继续往下判断循环条件执行语句 50 ll ans=fastpow(x,n-1)%n; 51 if(ans!=1) 52 return 0; 53 } 54 return 1; 55 } 56 int main() 57 { 58 //srand(time(0)); 59 //scanf("%lld",&n); 60 cin>>n; 61 for(int i=1;i<=n;i++) 62 { 63 if(check(i)) printf("%d\n",i); 64 } 65 return 0; 66 }
七、威尔逊定理
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6769677.html
ps:轻易不要用~~~
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 6 using namespace std; 7 8 long long int f(int p) 9 { 10 if(p==0) 11 return 1; 12 else return p*f(p-1); 13 } 14 int main() 15 { 16 int n; 17 scanf("%d",&n); 18 long long int ans=f(n-1); 19 if(ans%n==n-1) 20 printf("YES"); 21 else 22 printf("NO"); 23 return 0; 24 }
八、Catalan数
前一百:http://www.cnblogs.com/zxqxwnngztxx/p/6628239.html
1 #include<iostream> 2 3 using namespace std; 4 5 long long int f[1001]; 6 7 int main() 8 { 9 int n; 10 f[2]=1; 11 f[3]=1; 12 cin>>n; 13 n=n+2; 14 for(int i=4;i<=n;i++) 15 { 16 for(int j=2;j<=n-1;j++) 17 { 18 f[i]=f[j]*f[i-j+1]+f[i]; 19 } 20 } 21 cout<<f[n]; 22 return 0; 23 }
九、高精度
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; const int M = 500; char a1[M],b1[M]; int lena,lenb,lenc,x; int a[M],b[M],c[2*M]; bool ok=false; //全局变量,判断是否需要交换a1与b1 //add, subtract, multiply and divide void emm() { //初始化 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); } void change() { //进行转化 lena=strlen(a1); lenb=strlen(b1); for(int i=0; i<lena; ++i) a[lena-i]=(a1[i]-'0'); //转化为数字(逆序) for(int i=0; i<lenb; ++i) b[lenb-i]=(b1[i]-'0'); } void print() { for(int i=lenc; i>=1; i--) printf("%d",c[i]); printf("\n"); } void add() { //加 printf("add:\n"); emm(); change(); lenc=1,x=0; while(lenc<=lena||lenc<=lenb) { c[lenc]=a[lenc]+b[lenc]+x; x=c[lenc]/10; c[lenc]%=10; lenc++; } c[lenc]=x; //可能产生进位 if(!c[lenc] && lenc>1) lenc--; //(也可能并没有产生进位)去除前导'0' print(); } void subtract() { //减 printf("subtract:\n"); emm(); change(); bool fu=false; //判断是否需要输出负号 if(lena<lenb || (lena==lenb && strcmp(a1,b1)<0)) { //比较哪个数更加大一些 swap(a1,b1);//小数减去大数一定为负数 fu=true; } change(); //可能进行了位置的变化,此时进行更新len的长度 lenc=1; while(lenc<=lena) { if (a[lenc]<b[lenc]) { //如果较大的那位数的当前位数减去较小的那位数的当前位数不够减 a[lenc]+=10; //进行借位 a[lenc+1]--; //对应的下一位高位进行减1 (数学知识...) } c[lenc]=a[lenc]-b[lenc]; //进行计算 lenc++; } while(!c[lenc] && lenc>1) lenc--; //去除前导'0' if(fu) { printf("-"); ok=true; //判断a1与b1是否发生变化 } print(); } void multiply() { //乘 printf("multiply:\n"); emm(); if(ok) swap(a1,b1); change(); lenc=1,x=0; for(int i=1; i<=lena; i++) { x=0; //存放进位 for(int j=1; j<=lenb; j++) { c[i+j-1]=a[i]*b[j]+x+c[i+j-1]; //当前乘积+上次乘积进位+原数 x=c[i+j-1]/10; c[i+j-1]%=10; } c[i+lenb]=x; //进行进位操作 } lenc=lena+lenb; while(c[lenc]==0 && lenc>1) lenc--; //删除前导零 print(); } void divide() { //除 (Ps:高精除以低精(整除)) printf("divide:\n"); emm(); x=0; int dis; printf("Please enter the divisor:\n"); scanf("%d",&dis); int len=strlen(a1); for(int i=0; i<len; ++i) a[i+1]=a1[i]-'0'; for(int i=1; i<=len; i++) { c[i]=(x*10+a[i])/dis; x=(x*10+a[i])%dis; } lenc=1; while(c[lenc]==0 && lenc<lena) lenc++; //删除前导零 for(int i=lenc; i<=lena; i++) printf("%d",c[i]); printf("\n"); } int main() { scanf("%s%s",a1,b1); //此处一定不要加'&'符!!! add(); subtract(); multiply(); divide(); //默认a1是被除数 printf("End."); return 0; }
update at [2017-11-06]
//参考自Candy? #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int Mod = 10; struct Big { int a[520],n; int& operator [](int x) {return a[x];} Big() : n(0) {memset(a,0,sizeof(a));} void ini(int x) {a[++n]=x;} }; Big operator * (Big a,Big b) { Big c; for(int i=1; i<=a.n; i++) { int q=0; for(int j=1; j<=b.n; j++) q+=c[i+j-1]+a[i]*b[j],c[i+j-1]=q%Mod,q/=Mod; c[i+b.n]=q; } c.n=a.n+b.n; while(c.n>1 && c[c.n]==0) c.n--; return c; } Big operator * (Big a,int b) { int q=0; for(int i=1; i<=a.n; i++) q+=a[i]*b,a[i]=q%Mod,q/=Mod; while(q) a[++a.n]=q%10,q/=10; return a; } Big operator + (Big a,Big b) { int q=0,n=max(a.n,b.n); for(int i=1; i<=n; i++) { q+= i<=a.n ? a[i] : 0; q+= i<=b.n ? b[i] : 0; a[i]=q%Mod,q/=Mod; } a.n=n; if(q) a[++a.n]=q; return a; } Big operator - (Big a,Big b) { for(int i=1; i<=b.n; i++) { if(a[i]<b[i]) a[i]+=Mod,a[i+1]--; a[i]-=b[i]; } int q=b.n+1; while(a[q]<0) a[q]+=Mod,a[++q]--; while(a.n>1 && a[a.n]==0) a.n--; return a; } void Print(Big &a) { for(int i=a.n; i>=1; i--) printf("%d",a[i]); } string s1,s2; int main() { cin>>s1>>s2; int len1=s1.length(),len2=s2.length(); Big a,b,c; for(int i=len1-1; i>=0; i--) a.ini(s1[i]-'0'); for(int i=len2-1; i>=0; i--) b.ini(s2[i]-'0'); //c=...; c=a+b; Print(c); return 0; }
十、逆元
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6880386.html
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int a,b,m; int x,y; int exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1; y=0; return a; } int r=exgcd(b,a%b,x,y),tmp; tmp=x,x=y; y=tmp-a/b*y; return r; } int fastpow(int a,int p) { int bb=a;int ans=1; while(p!=0) { if(p%2==1)ans=ans*bb; bb=bb*bb; p=p/2; } return ans; } int main() { scanf("%d%d%d",&a,&b,&m); for(int i=1;i<=sqrt(m);i++) { if(m%i==0) { int ans=exgcd(b,m,x,y); printf("%d",(a*ans)%m); return 0; } } printf("%d",fastpow(b,m-2)); }
十一、BSGS!
详细请见:http://www.cnblogs.com/zxqxwnngztxx/p/6880136.html
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<cmath> using namespace std; typedef long long LL; LL a,b,c; map<LL,LL> mp; LL qsm(LL m) { LL n = a; if(m == 0) return 1; LL t = qsm(m/2); t = 1LL*t*t%c; if(m&1) t = 1LL*t*n%c; return t; } int main() { //a^im=b*a^j(mod c) while (scanf("%lld%lld%lld",&c,&a,&b)!=EOF) { mp.clear(); //清空 if (a%c==0) //判断a,c 是否互质,因为c 是质数,所以直接判断是否整除即可 { printf("no solution\n"); continue; } LL m=ceil(sqrt(c)); LL ans; for (LL j=0; j<=m; j++) { if (j==0) { //当j=0时,a^j=1, b*a^j=b ans=b%c; mp[ans]=j; continue; } ans=(ans*a)%c; //括号里的ans指a^(j-1)*b,(a^(j-1)*b)*a=(a^j)*b mp[ans]=j;//在((a^j)*b)%c的位置记录下j } LL t=qsm(m);//t=a^m ans=1; bool p=false; for (LL i=1; i<=m; i++) { ans=(ans*t)%c;//括号里的ans指的是((a^m)^(i-1))*(a^m)=(a^m)^i=a^(im) if (mp[ans]) { LL t=i*m-mp[ans];//t=x,因为我们设的x=i*m-j printf("%lld\n",t); p=true; break; } } if (!p) printf("no solution\n"); } }
暂时的End.
(不定时更.看我学到哪里咯?哈哈哈)