今天讲数论
1.进制问题(将n转换成k进制数):
1.方法:短除法
将n/k,保存,将商当做新的n,将余数保存,直到商为0,将余数(包括0),倒序输出,即得n的k进制数
2.关于高精四则运算(我本以为不用怎么整的):
举个加和乘的例子...
众所周知,a+b problem是最简单的红题,再加个*也无伤大雅,代码如下(没文件头):
int main(){ int a,b; cin>>a>>b; cout<<a*b; return 0; }
直到你加了这些东西:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct nu{ 4 int a[100005]; 5 int l; 6 nu(){ 7 l=1; 8 memset(a,0,sizeof(a)); 9 } 10 friend istream& operator>>(istream &cin,nu &x){ //意思是:重载>>(用于cin,读到x里面) 11 static char s[100005]; 12 cin>>s; 13 int l=strlen(s); 14 for(int i=0;i<=l;i++) 15 x.a[i]=s[l-i-1]-'0'; 16 x.l=l; 17 return cin; 18 } 19 friend ostream& operator<<(ostream &cout,const nu &x){ //与上面大同,多了个const,在于使x值在输出前后值相同 20 for(int i=x.l-1;i>=0;i--) 21 cout<<x.a[i]; 22 } 23 }; 24 nu operator+(const nu &x,const nu &y){ //重载+ 25 nu ans; 26 int len=max(x.l,y.l); 27 for(int i=0;i<len;i++) 28 ans.a[i]+=x.a[i]+y.a[i]; 29 for(int i=0;i<len;i++){ 30 if(ans.a[i]>=10){ 31 int now=ans.a[i]/10; 32 ans.a[i+1]+=now; 33 ans.a[i]%=10; 34 } 35 while(ans.a[len+1]) len++; 36 } 37 ans.l=len; 38 return ans; 39 } 40 nu operator*(const nu &x,const nu &y){ //重载*用了非常简单而经典的高精算法 41 nu ans; 42 for(int i=0;i<x.l;i++) 43 for(int j=0;j<y.l;j++) 44 ans.a[i+j]+=x.a[i]*y.a[j]; 45 ans.l=x.l+y.l; 46 for(int i=0;i<ans.l;i++){ 47 ans.a[i+1]+=ans.a[i]/10; 48 ans.a[i]%=10; 49 } 50 while(ans.l>0&&!(ans.a[ans.l])) 51 ans.l--; 52 ans.l++; 53 return ans; 54 } 55 int main(){ 56 nu a,b; 57 cin>>a>>b; 58 cout<<a*b; 59 return 0; 60 }
6-9行是构造函数,用于memset
10-22是重载cin与cout,背过就好
加const的原因是进行运算的值由符号返回,而从不是变量本身,所以没有赋值的话不能改变变量的值,也更方便电脑理解,可以看到stl里面好多函数用了const
至于&符号,用因如下:
每次用函数运算时,每个函数形如 f(int n),都要把用的变量“n”的值拷贝一份进行运算,如果引用数组就更慢,还更占内存,用了&符号意在免去拷贝操作,直接引用其值,
(反正有了const不用怕数值变化)这就算一个优化
后面一直到主函数之前都是重载运算符
3.关于素数(又是各种筛法)
粘下模板:
1.埃氏筛:
#include<bits/stdc++.h> using namespace std; bool no[10005]={1,1}; int pri[10000]; int tot; inline void p(int t){ for(int i=1;i<=t;i++) if(!no[i]){ pri[++tot]=i; for(int j=i+i;j<=t;j+=i) no[j]=1; } } int n; int main(){ scanf("%d",&n); p(n); for(int i=1;i<=tot;i++)printf("%d ",pri[i]); return 0; }
欧拉筛(线性筛):
#include<bits/stdc++.h> using namespace std; bool no[10005]; int pri[10000]; int tot; int n; inline void p(int n){ for(int i=2;i<=n;i++){ if(!no[i]) pri[++tot]=i; for(int j=1;j<=n&&i*pri[j]<=n;j++){ no[i*pri[j]]=1; if(!(i%pri[j])) break; } } } int main(){ scanf("%d",&n); p(n); for(int i=1;i<=tot;i++)printf("%d ",pri[i]); return 0; }
3.exgcd:
#include<bits/stdc++.h> using namespace std; int a,b,x,y; inline int exgcd(int a,int b,int &x,int &y){ //利用性质gcd(a,b)=gcd(b,a%b) if(!b){ x=1; y=0; return a; }int g=exgcd(b,a%b,x,y); int t=x; x=y; y=(t-(a/b)*x); return g; } int main(){ cin>>a>>b; exgcd(a,b,x,y); if(x<0) x+=b; cout<<x; return 0; }
练多了不解释...
下午考试了..我..应该..大概不会爆零