数学瞎整理
一.质数
1.筛质数:有两种 一个线性筛,一个欧拉筛。一般用欧拉筛就行了,如果是求一个[l,r] l r大但差的绝对值小的区间,先用线性筛筛前面,然后用欧拉筛筛后面
欧拉筛O(N log log N):注意每次i循环从2开始 j从i开始
1 bool v[N]; 2 int n; 3 void prime(int n) 4 { 5 memset(v,0,sizeof(v)); 6 for(int i=2;i<=n;i++) 7 { 8 if(v[i]) continue; 9 cout<<i<<" "; 10 for(int j=1;j<=n/i;j++) v[i*j]=1; 11 } 12 }
线性筛 O(N):j从1开始
1 void primes(int n) 2 { 3 memset(v,0,sizeof(v)); 4 cnt=0; 5 for(int i=2;i<=n;i++) 6 { 7 if(!v[i]) prime[++cnt]=i,v[i]=i; 8 for(int j=1;j<=cnt;j++) 9 { 10 if(prime[j]>v[i]||prime[j]>n/i) break; 11 v[i*prime[j]]=prime[j]; 12 } 13 } 14 for(int i=1;i<=cnt;i++) 15 cout<<prime[i]<<" "; 16 }
2.质因数分解:试除法。 结合欧拉筛,扫描2~ √N的每个数d, 若d整除N,从N中除掉所有因子d,同时累计除去的d的个数。
1 void divide(int n) 2 { 3 cnt=0; 4 for(int i=2;i*i<=n;i++) 5 { 6 if(n%i==0) 7 { 8 prime[++cnt]=i; c[cnt]=0; 9 while(n%i==0) n/=i,c[cnt]++; 10 } 11 } 12 if(n>1) prime[++cnt]=n,c[cnt]=1; 13 for(int i=1;i<=cnt;i++) 14 cout<<prime[i]<<"^"<<c[i]<<endl; 15 }
3.example
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define N 10000010 4 #define mod 998244353 5 using namespace std; 6 ll prime[N],cnt,v[N]; 7 ll L,R,ans,ans2; 8 void pre() 9 { 10 for(int i=2;i<1000000;i++) 11 { 12 if(v[i]==0) v[i]=i,prime[++cnt]=i; 13 for(int j=1;j<=cnt;j++) 14 { 15 if(prime[j]>v[i]||prime[j]>1000000/i) break; 16 v[i*prime[j]]=prime[j]; 17 } 18 } 19 } 20 int main() 21 { 22 pre(); 23 scanf("%lld%lld",&L,&R); 24 memset(v,0,sizeof(v)); 25 for(ll i=1;i<=cnt;i++) 26 { 27 ll st=max(1ll,(L-1)/prime[i])*prime[i]+prime[i]; 28 for(ll j=st;j<=R;j+=prime[i]) 29 { 30 if(v[j-L]) continue; 31 v[j-L]=1; 32 ans++; 33 ans2=(ans2+prime[i])%mod; 34 } 35 } 36 printf("%lld %lld",ans,ans2); 37 return 0; 38 }
二.约数
-
求约数(集合)
1.试除法:略
有一推论:一个整数N的约数个数上界为2√N
2.倍数法
推论:1~N每个数的约数个数的总和约为 N log N
1 vector<int> f[N]; 2 int n; 3 void pu(int n) 4 { 5 for(int i=1;i<=n;i++) 6 for(int j=1;j<=n/i;j++) 7 f[i*j].push_back(i); 8 for(int i=1;i<=n;i++){ 9 for(int j=0;j<f[i].size();j++) 10 cout<<f[i][j]<<" "; 11 cout<<endl; 12 } 13 }
3.example 反素数
见P134
1 #include<bits/stdc++.h> 2 #define N 2000000000 3 #define ll long long 4 using namespace std; 5 ll n; 6 ll ans; 7 int num=1; 8 int a[11]={0,2,3,5,7,11,13,17,19,23,29}; 9 void dfs(int dep,int dex,ll anss,int cnt) 10 { 11 if(dep==10) 12 { 13 if((anss>ans&&cnt>num)||(anss<=ans&&cnt>=num)) 14 { 15 ans=anss; 16 num=cnt; 17 } 18 return; 19 } 20 int t=1; 21 for(int i=0;i<=dex;i++) 22 { 23 dfs(dep+1,i,anss*t,cnt*(i+1)); 24 t*=a[dep]; 25 if(anss*t>n) break; 26 } 27 } 28 int main() 29 { 30 scanf("%lld",&n); 31 dfs(1,30,1,1); 32 printf("%lld\n",ans); 33 return 0; 34 }
-
gcd
1.定理:
-
gcd(a,b)*lcm(a,b)=a*b
-
gcd(a,b)=gcd(b,a-b)=gcd(a,a-b) (a>=b)
- gcd(a,b)=gcd(b,a mod b) (b!=0)
2.一行gcd:
1 int gcd(int a,int b) 2 { 3 return b?gcd(b,a%b):a; 4 }
3.example hankson
贼毒了...我是用暴力写的....还用了自带函数__gcd()
1 #include<bits/stdc++.h> 2 #define N 20000100 3 #define ll long long 4 using namespace std; 5 ll f[N]; 6 int cnt; 7 ll a0,a1,b0,b1; 8 int i; 9 void div(int x) 10 { 11 cnt=0; 12 for(i=1;i*i<=x;i++) 13 if(x%i==0) 14 { 15 f[++cnt]=i; 16 if(i!=x/i) f[++cnt]=x/i; 17 } 18 } 19 ll ans; 20 void red(ll &x) 21 { 22 ll f=1;x=0;char c=getchar(); 23 while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} 24 while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();} 25 x*=f; 26 } 27 void print(ll x) 28 { 29 if(x<0) putchar('-'),x=-x; 30 if(x>9) print(x/10); 31 putchar(x%10+'0'); 32 } 33 int main() 34 { 35 ll t; 36 red(t); 37 while(t--) 38 { 39 red(a0);red(a1);red(b0);red(b1); 40 div(b1); 41 ans=0; 42 for(i=1;i<=cnt;i++) 43 { 44 ll yy=__gcd(f[i],b0); 45 if(b0*f[i]/yy!=b1) continue; 46 if(__gcd(f[i],a0)==a1) ans++; 47 } 48 printf("%lld\n",ans); 49 } 50 return 0; 51 }
三.互质和phi
1.phi(i)指1~i之间与i互质的数个数
2.
代码如下:
1 int phi(int n) 2 { 3 int ans=n; 4 for(int i=2;i*i<=n;i++) 5 if(n%i==0) 6 { 7 ans=ans/i*(i-1); 8 while(n%i==0) n/=i; 9 } 10 if(n>1) ans=ans/n*(n-1); 11 return ans; 12 }
3.性质 (p均为质数)
- 任意n>1,1~n中与n互质的数的和为 n * phi(n) / 2 ;
- 若a,b互质,phi(a*b)=phi(a)*phi(b);
- 若p|n 且 p^2|n, 则phi(n)=phi(n/p)*p;
- 若p|n 但不满足 p^2|n,则phi(n/p) * (p-1);
- ∑d|n phi(n)=n;
四.同余
- PRE
1.费马小定理:
2.欧拉定理:若正整数a,n 互质
3. 欧拉定理的推论:
(mod n)
由此,我们在计算乘方算式需要取模时,可以先把底数对p取模,指数对phi(p)取模,再计算乘方
- EXGCD和逆元
1.exgcd: 用于计算x,y 使得对于任意整数a,b, 存在一对整数x,y,满足ax+by=gcd(a,b)
所以 :
1 int exgcd(int a,int b,int &x,int &y) 2 { 3 if(b==0) { x=1; y=0;return a; } 4 int d=exgcd(b,a%b,y,x); 5 y-=a/b*x; 6 return d; 7 } 8 //d=exgcd(a,b,x0,y0);
调用函数可求得 ax + by = gcd ( x, y ) 的一组特解,d 为 gcd ( a , b )