2019矿大icpc夏令营Day3-数论

数论的编程实验

之前曾好几次学过数论,但是其中各种证明方法以及理论仍然是转眼间就忘。借着这次机会,要把模板以及常用的定理以及推论给掌握。今天讲的高斯素数、梅森素数都是第一次听说,回头要重新写一篇笔记详细学习一下。还有将正整数快速分解成质因数的Pollard_rho算法还没有掌握,也要写一篇笔记学习并整理。

求解不定方程和同余方程

  • 计算最大公约数和不定方程
  • 计算同余方程和同余方程组
  • 计算多项式同余方程

欧几里得算法

POJ2773 Happy2006

找周期(循环节?)

#include
const int M = 1e6+10;
int a[M];
int m,k,tot = 0;
int gcd(int a,int b){
	if(b == 0) return a;
	return gcd(b,a%b);
}
void solve(){
	tot = 0;
	for(int i = 1;i <= m;i++)
		if(gcd(m,i) == 1) a[tot++] = i;
	int tmp = k/tot , r = k%tot-1;
	if(r != -1) printf("%d\n",m*tmp+a[r]);
	else printf("%d\n",m*(tmp-1)+a[tot-1]);
}
int main(){
	while(scanf("%d%d",&m,&k) != EOF){
		solve();
	}
	return 0;
}

线性组合

求不定方程整数根方法:

  • 枚举
  • 拓展欧几里得算法
POJ2142 Balance

用拓展欧几里得算法求得所有的解,其中|x|+|y|最小的为所求答案。
来自老师的代码,用的方法是:先令一个数为正,再求另一个解,然后取最小值。

#include 
#include 
int exgcd(int a, int b, int &x, int &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    int gcd = exgcd(b, a%b, y, x);
    y -= a / b * x;
    return gcd;
}
int main() {
    int a, b, d, x, y, x1, y1, x2, y2;
    while (~scanf("%d%d%d", &a, &b, &d) && (a||b||d)) {
        int gcd = exgcd(a, b, x, y);
        a /= gcd, b /= gcd, d /= gcd, x *= d, y *= d;
        x1 = (x%b+b) % b, y1 = (d - a*x1) / b;
        y2 = (y%a+a) % a, x2 = (d - b*y2) / a;
        if (x1+abs(y1) > abs(x2)+y2) x1 = abs(x2), y1 = y2;
        printf("%d %d\n", abs(x1), abs(y1));
    }
    return 0;
}
zoj3595 One Person Game

拓展欧几里得,然后对xy进行讨论,看能够用c替代a+b。

POJ1995 Raising Modulo Numbers

简单的模运算规则应用。

#include
typedef long long ll;
int z,m,k;
ll qpow(ll a,ll b,ll p){
	ll res = 1;
	while(b){
		if(b&1) res = res*a%p;
		a = a*a%p;
		b >>= 1;
	}
	return res;
}
int main(){
	scanf("%d",&z);
	while(z--){
		scanf("%d%d",&m,&k);
		ll ans = 0;
		for(int i = 1,x,y;i <= k;i++){
			scanf("%d%d",&x,&y);
			ans = (ans+qpow(x,y,m))%m;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

特殊的同余式

  • 威尔逊定理与费马小定理
  • 伪素数
  • 欧拉定理
POJ3641 Pseudoprime numbers

费马小定理的简单应用。

#include
#include
typedef long long ll;
int testnum[] = {2,3,5,61,7,11,13,19};
inline ll fmul(ll a,ll b,ll p){
    return a*b%p;
}
ll qpow(ll a,ll b,ll m){    //快速幂算法 
    ll res = 1;
    while(b){
        if(b&1) res = fmul(res,a,m);
        a = fmul(a,a,m);
        b >>= 1;
    }
    return res;
}

bool isPrime(ll n){ 
    if(n == 2 || n == 3 || n == 5) return true;
    if(n < 2 || n%2 == 0) return false;
    ll d = n-1 , a, x, y; int t = 0;
    while((d&1) == 0) d >>= 1,t++;
    //此时b为没有因子2的奇数 
    for(int i = 0;i < 5;i++){
        a = testnum[i];
        if(n == a) return true;
        x = qpow(a,d,n);
        //我们要使得所有的a(^(2^r)*d)都满足二次探测定理 
        for(int j = 0;j < t;j++){
            y = fmul(x,x,n);        
            if(y == 1 && x != 1 && x != n-1) return false;
            x = y;  
        } 
        if(x != 1) return false;//不满足费马小定理 
    }
    return true;    
    //当x=n-1,或b为奇数时返回true; 
}
int main(){
	ll a,p;
	while(~scanf("%lld%lld",&p,&a) && (a || p)){
		if(isPrime(p)) puts("no");
		else{
			if(qpow(a,p,p) == a) puts("yes");
			else puts("no");
		} 
	}	
	return 0;
} 
HDOJ2138 How many prime numbers

Miller-Rabin模板题。

#include
#include
const int N = 1e6+10;
int num[N];
typedef long long ll;
int testnum[] = {2,3,5,5,7,11,13,19};
inline ll fmul(ll a,ll b,ll p){
    return a*b%p;
}
ll qpow(ll a,ll b,ll m){    //快速幂算法 
    ll res = 1;
    while(b){
        if(b&1) res = fmul(res,a,m);
        a = fmul(a,a,m);
        b >>= 1;
    }
    return res;
}

bool isPrime(ll n){ 
    if(n == 2 || n == 3 || n == 5) return true;
    if(n < 2 || n%2 == 0) return false;
    ll d = n-1 , a, x, y; int t = 0;
    while((d&1) == 0) d >>= 1,t++;
    //此时b为没有因子2的奇数 
    for(int i = 0;i < 5;i++){
        a = testnum[i];
        if(n == a) return true;
        x = qpow(a,d,n);
        //我们要使得所有的a(^(2^r)*d)都满足二次探测定理 
        for(int j = 0;j < t;j++){
            y = fmul(x,x,n);        
            if(y == 1 && x != 1 && x != n-1) return false;
            x = y;  
        } 
        if(x != 1) return false;//不满足费马小定理 
    }
    return true;    
    //当x=n-1,或b为奇数时返回true; 
}
int main(){
	int n;
	while(scanf("%d",&n) != EOF){
		ll x;int ans = 0;
		for(int i = 1;i <= n;i++){
			scanf("%lld",&x);
			if(isPrime(x)) ans++;
		}
		printf("%d\n",ans);
	}
}
POJ1181 Prime Test

Pollard_rho算法以及Miller-Rabin算法的应用。

Goldbach’s Conjecture

哥德巴赫猜想相关题,考察简单的素数筛,O(N log N)即可。

#include
typedef long long ll;
const int N = 1e6+10;
int isPrime[N];
int n;
void init(){
	for(int i = 2;i*i < N;i++) if(!isPrime[i]){
		for(int j = i*i;j < N;j += i) isPrime[j] = 1;
	}
	//for(int i = 1;i <= 100;i++) printf("%d:%d ",i,isPrime[i]);
}
void solve(){
	for(int i = 2;i <= n/2;i++){
		if(!isPrime[i] && !isPrime[n-i]){
			printf("%d = %d + %d\n",n,i,n-i);	
			break;
		}
	}
}
int main(){
	init();
	while(~scanf("%d",&n) && n){
		solve();
	}
	return 0;
}
Summation of Four Primes

类似于上一题,因为我们已知任意一个大于4的偶合数都可以分为俩个素数的和(哥德巴赫猜想),那么显然小于8的就无解,而大于8的数,可以根据其奇偶选择-4(2 、 2)或-5(2 、3),再将剩下的偶合数分解即可。

#include
const int N = 1e7+10;
int isPrime[N];
int n;
void init(){
	for(int i = 2;i*i < N;i++) if(!isPrime[i]){
		for(int j = i*i;j < N;j += i) isPrime[j] = 1;
	}
	//for(int i = 1;i <= 100;i++) printf("%d:%d ",i,isPrime[i]);
}
void solve(){
	if(n&1){
		n -= 5;
		printf("2 3 ");
	} else {
		n -= 4;
		printf("2 2 ");
	}
	for(int i = 2;i <= n/2;i++){
		if(!isPrime[i] && !isPrime[n-i]){
			printf("%d %d\n",i,n-i);
			break;
		}
	}
	
}
int main(){
	init();
	while(scanf("%d",&n)!=EOF){
		if(n < 8) puts("Impossible.");
		else solve();
	}
	return 0;
}
Prime Gap

线性筛+二分查找

#include
const int N = 2e6+10;
int primes[N],v[N],tot;
void init(){
	for(int i = 2;i < N;i++){
		if(!v[i]){
			v[i] = i;
			primes[tot++] = i;
		}
		for(int j = 0;j < tot;j++){
			if(primes[j]*i >= N || primes[j] > v[i]) break;
			v[i*primes[j]] = primes[j];
		}
	}
	//for(int i = 0;i < 100;i++) printf("%d ",primes[i]);
}
int n;
void solve(){
	int l = 0,r = tot;
	while(l <= r){
		int mid = l+r>>1;
		if(primes[mid] > n) r = mid-1;
		else l = mid+1;
	}
	if(primes[r] == n) puts("0");
	else printf("%d\n",primes[r+1]-primes[r]);
}
int main(){
	init();
	while(~scanf("%d",&n) && n){
		solve();
	}
	return 0;
}

完全数和梅森素数

POJ1528 Perfection

想办法求出真约数即可。

POJ1777 Vivian‘s Problem

梅森素数的题。

你可能感兴趣的:(假期练习)