ACM培训4

学习总结--基础数论

大多为模板

一、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);
    }
}

二、乘法逆元

定义:给定模m和整数a(满⾜gcd(a,m)=1 ),称整数 a为 关于模 m的乘法逆元,如果满⾜a*x与1同余mod(m),记作a^-1;
存在条件
乘法逆元存在的充要条件是 a与 m互质,即 gcd(a,m)=1。
 
常用于运算:b÷a(modp)=(b(modp)×a ^-1(modp))(modp)
 
扩展欧几里得算法求逆元
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); }

三、线性筛

1.使⽤⼀个布尔数组标记每个数是否为合数(⾮素数)。
2. 利⽤⼀个数组保存筛出的素数。
3. 对于每个整数  i :
    若 i 未被标记,则 i 为素数,加⼊素数列表。
    遍历已知素数列表,对于每个素数p :
    若 i*p<=n,则将 i*p标记为合数。
    如果 i 能被 p整除,则停⽌该次遍历(保证每个合数只被标记⼀次)。
模板
#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代码

#include
using namespace std;
long long n,l,r;
int main(){
	cin>>n;
	for(long long i=1;i<=n;i++){
		cin>>l>>r;
		if(l==r&&l==1) cout<<1<

 

 

洛谷--P2613

1.乘法逆元模板题

2.数据超出long long 范围,需高精度处理

3.但本题求余数,所以快速读入时取余就行

4.随时取余是个好习惯

AC代码

#include
using namespace std;
inline long long read()
{
	char c=getchar();int x=0,f=1;
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar()) x=(x*10+c-48)%19260817;
	return x*f;
}
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); }
int main(){
	long long a,b,sum;
	a=read(),b=read();
	if(b==0){
		cout<<"Angry!";
		return 0;
	}
	long long d=modInverseFast(b,19260817);
		d%=19260817;
		sum=d*a%19260817;
		cout<

 

 

你可能感兴趣的:(算法,笔记)