学习总结--基础数论
大多为模板
一、GCD(最大公约数)
①辗转相除法
long long gcd(long a,long b){
long long r;
while(b!=0){
r=a%b;
a=b;
b=r;
}
return a;
}
②扩展欧几里得算法
int exgcd(int a,int b,int &x,int &y){
if(b==0) {x=1;y=0;return aa;}
int ans=exgcd(b,a%b,x,y);
int k=x;
x=y;
y=k-a/b*y;
return ans;
}
③解二元一次方程
int exgcd(int a,int b,int &x,int &y){
if(b==0) {x=1;y=0;return aa;}
int ans=exgcd(b,a%b,x,y);
int k=x;
x=y;
y=k-a/b*y;
return ans;
}
void work(){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int x,y;
int d=exgcd(a,b,x,y);
if(c%d) printf("Impossible\n");
else{
int x0=x*c/d,y0=y*c/d;//特解
int p=b/d,q=a/d;
printf("通解为:x=%d+%dt,y=%d-%dt",x0,p,y0,q);
}
}
二、乘法逆元
long long modinverse(long long a,long long m){
int x,y;
int g=exgcd(a,m,x,y);
if(g!=1) return -1;
x%=m;
if(x<0) x+=m;
return x;
}
快速幂求逆元
long long modExp(long long a,long long b,long long mod){
long long res=1;
a%=mod;
while(b>0){
if(b&1) res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
long long modInverseFast(long long a, long long m){
return modExp(a,m-2,m); }
三、线性筛
#include
using namespace std;
int pos=0,ans=0;
const int N=1e6+1;
int arr1[N]={0};
int primes[N]={0};
int main(){
for(int i=2;i<=1e6;i++){
if(!arr1[i]) primes[++pos]=i;
for(int j=1;j<=pos;j++){
if(i*primes[j]>1e6)break;
arr1[i*primes[j]]=1;
if(i%primes[j]==0) break;
}
}
return 0;
}
解题思路及代码
Codeforces-2029E
本题重在分析
1.质素数量>=2,无法找到,输出-1 (质素只能由其本身生成)
2. 质素数量=0,输出2 (任意和数都可以由2得到)
3.质素数量=1,记为p,q为p的最小奇数因子
①序列中合数应>=2*p
②p-q>=2*p
AC代码
#include
using namespace std;
int t,n,m;
const int N=1e6+1;
int a[N],num,countt=0,y=1;
int fj(int n){
int nn=sqrt(n);
for(int i=2;i<=nn+1;i++){
if(n%i==0) return i;
}
return n;
}
int fj1(int n){
int nn=sqrt(n);
for(int i=2;i<=nn+1;i++){
if(n%i==0&&i%2!=0) return i;
}
return n;
}
int main(){
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%d",&n);
for(int j=1;j<=n;j++){
scanf("%d",&a[j]);
if(fj(a[j])==a[j]) num=a[j],countt++;
}
if(countt>=2) printf("-1\n");
if(countt==0){
printf("2\n");
}
if(countt==1){
for(int j=1;j<=n;j++){
if(a[j]!=num){
if(a[j]%2==0){
if(a[j]
Cdeforces-632D
lcm与该序列的数的位置无关,记录每个数的因子个数,做法与筛类似
AC代码
#include
using namespace std;
const int N = 1e6+2;
int a[N],b[N],c[N];
int main(){
int n,m,l=0,k=0,flag=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]<=m){
flag=1;
b[a[i]]++;
}
}
if(flag==0){
cout<<1<<" "<<0<k) k=c[i],l=i;
}
cout<
洛谷-P1029
1.P , Q必介于a与b间
2.lcm(a,b)*gcd(a,b)=a*b;
3.暴力遍历,用gcd判断是否符合
所以归根是gcd
AC代码
#include
using namespace std;
long long gcd(long a,long b){
long long r;
while(b!=0){
r=a%b;
a=b;
b=r;
}
return a;
}
int a,b,ans=0;
int main(){
cin>>a>>b;
int c=a*b;
for(int i=a;i<=b;i++){
if(c%i==0){
if(gcd(i,c/i)==a) ans++;
}
}
cout<
洛谷-P1835
1.数据量大,暴力超时
2.用线性筛筛出1-5e4的素数,记录成表
3.遍历区间,看是否可以被表中素数整除
AC代码
#include
using namespace std;
int l,r,pos=0,ans=0;
const int N=1e6+1;
int arr1[N]={0};
int primes[N]={0};
int main(){
cin>>l>>r;
for(int i=2;i<=5e4;i++){
if(!arr1[i]) primes[++pos]=i;
for(int j=1;j<=pos;j++){
if(i*primes[j]>1e6) break;
arr1[i*primes[j]]=1;
if(i%primes[j]==0) break;
}
}
for(int i=l;i<=r;i++){
if(i==1) ans--;
int flag=1;
for(int j=1;j<=pos;j++){
if(primes[j]>=i)break;
if(i%primes[j]==0){
flag=0;
break;
}
}
if(flag==1) ans++;
}
cout<
Codeforces--2063A
水题,分三种情况,l=r=1, l=r !=1, l AC代码 洛谷--P2613 1.乘法逆元模板题 2.数据超出long long 范围,需高精度处理 3.但本题求余数,所以快速读入时取余就行 4.随时取余是个好习惯 AC代码 #include
#include