51nod 数论专题 (按分值排序)(持续更新)

#查找某篇题解:ctrl+f

#1 .51nod 1011

gcd,不解释

代码:

int gcd(a, b){
	return b ? gcd(b, a%b) : a;
}

#2 .51nod 1135

求最小原根

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define mem(a,b) memset(a, b, sizeof(a))
#define LL long long

using namespace std;

const int maxn = 1000005;

int yue[maxn], tot, cnt;
int v[maxn], prime[maxn]; 

void is_prime(){
	mem(v,1);
	for(int i = 2; i <= maxn; i++){
		if(v[i]){
			prime[++cnt] = i;
			for(int j = i; j <= maxn; j += i){
				v[j] = 0;
			}
		}
	}
}

void div(int x){
	tot = 0;
	int t = (int)sqrt(1.0*x);
	for(int i = 1; prime[i] <= t; i++){
		if(x % prime[i] == 0){
			yue[++tot] = prime[i];
			while(x % prime[i] == 0) x /= prime[i];
		}
	}
	if(x > 1)
		yue[++tot] = x;
}

LL Pow(LL a, LL b, LL m){
	LL ans = 1;
	a %= m;
	while(b){
		if(b & 1)
			ans = ans * a % m;
		a = a * a % m;
		b >>= 1;
	}
	return ans;
}


int main(){
	int p;
	is_prime();
	while(scanf("%d", &p) == 1 && p){
		div(p-1);
		for(int i = 2; i <= p-1; i++){
			bool flag = 1;
			for(int j = 1; j <= tot; j++){
				int t = (p-1)/yue[j];
				if(Pow((LL)i, (LL)t, (LL)p) == 1){
					flag = 0;
					break;
				}
			}
			if(flag){
				printf("%d\n", i);
				break;
			}
		}
	}
return 0;
}

#3 .51nod 1046

快速幂

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

#define LL long long

using namespace std;

LL Pow(LL a, LL b, LL p){
	LL ans = 1LL;
	a %= p;
	while(b){
		if(b & 1)
			ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans;
}

int main(){
	LL a, b, c;
	scanf("%lld%lld%lld", &a, &b, &c);
	printf("%lld\n", Pow(a, b, c));
return 0;
}

#4. 51nod 1073

约瑟夫环

代码:

#include <iostream>

using namespace std;
int main(){
	int n, k;
	cin>>n>>k;
	int s = 0;
	for(int i = 1; i <= n; i++){
		s = (s + k) % i;
	}
	cout<<s+1<<endl;
return 0;
}

#5. 51nod 1256

乘法逆元(因为N不一定是素数,所以用exgcd求解)

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

#define LL long long

using namespace std;

void exgcd(LL a, LL b, LL &x, LL &y){
	if(b == 0){
		x = 1, y = 0;
		return;
	}
	exgcd(b, a%b, x, y);
	LL tmp = x;
	x = y;
	y = tmp - y * (a / b);
}

int main(){
	LL a, b, x, y;
	scanf("%lld%lld", &a, &b);
	exgcd(a, b, x, y);
	x = (x % b + b) % b;
	printf("%lld\n",x);
return 0;
}

#6. 51nod 1136

求欧拉函数值

代码:

#include <iostream>
#include <cmath>

using namespace std;

int phi(int n){
	int ans = n;
	for(int i = 2; i <= sqrt(n); i++){
		if(n % i == 0){
			ans = ans / i * (i-1);
			while(n % i == 0) n /= i;
		}
	}
	if(n > 1)	ans = ans / n * (n-1);
	return ans;
}

int main(){
	int n;
	cin>>n;
	cout<<phi(n)<<endl;
return 0;
}

#7 .51nod 1079

中国剩余定理

推荐博客:https://blog.csdn.net/acdreamers/article/details/8050018

https://www.cnblogs.com/MashiroSky/p/5918158.html

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long

LL exgcd(LL a, LL b, LL &x, LL &y){
	if(!b){
		x = 1, y = 0;
		return a;
	} 
	int d = exgcd(b, a%b, x, y);
	int tmp = x;
	x = y;
	y = tmp - (a/b)*y;
	return d;
}

LL CSD(int m[], int a[], int n){
	LL x  = 0, y, d;
	LL M = 1;
	LL ans = 0;
	for(int i = 1; i <= n; i++){
		M *= m[i];
	}
	for(int i = 1; i <= n; i++){
		LL Mi = M / m[i];
		d = exgcd(Mi, m[i], x, y);
		x = x/d;
		ans = (ans + a[i]*Mi*x) % M;
	}
	return (ans + M) % M;
}

int main(){
	int n, m[15], a[15];
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d %d", &m[i], &a[i]);
	}
	printf("%lld\n", CSD(m, a, n));
return 0;
}

#8. 51nod 1240
##莫比乌斯(mobius)函数
代码:

//求单个数的mobius值
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int c[1000005];

int main(){
	int n, ans = 0, m = 0;
	scanf("%d", &n);
	int nn = n;
	for(int i = 2; i <= sqrt(nn); i++){
		if(n % i == 0){
			c[++m] = 0;
			while(n % i == 0){
				n /= i;
				c[m]++;
			}
		}
	}	
	if(n > 1){
		c[++m] = 1;
	}
	for(int i = 1; i <= m; i++){
		if(c[i] >= 2){
			printf("0\n");
			return 0;
		}
	}
	if(m & 1){
		printf("-1\n");
	}
	else{
		printf("1\n");
	}
return 0;
}
//求2到n的mobius值
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int miu[1000005];
int v[1000005];
int n;

int main(){
	scanf("%d", &n);
	for(int i = 2; i <= n; i++) miu[i] = 1, v[i] = 0;
	for(int i = 2; i <= n; i++){
		if(v[i]) continue;
		miu[i] = -1;
		for(int j = 2*i; j <= n; j += i){
			v[j] = 1;
			if( (j / i) % i == 0 ) miu[j] = 0;
			else miu[j] *= -1;
		}
	}
	for(int i = 2; i <= n; i++){
		printf("%d ", miu[i]);
	}
return 0;
}

#9. 51nod 1106

质数检测, 水题

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int n, t;

bool is_prime(int x){
	for(int i = 2; i <= sqrt(x); i++){
		if(x % i == 0){
			return false;
		}
	}
	return true;
}

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d", &t);
		if(is_prime(t))
			printf("Yes\n");
		else printf("No\n");
	}
return 0;
}

#10. 51nod 1012
##lcm 算了还是不一个一个做了,这种水题。。。还是二分一下适合我的题。

#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long

using namespace std;

LL gcd(LL a, LL b){
	return b ? gcd(b, a%b) : a;
}



int main(){
	LL a, b;
	scanf("%lld %lld", &a, &b);
	printf("%lld\n", a/gcd(a ,b)*b);
return 0;
}

#11. 51nod 1181
题意:如果一个质数,在质数列表中的编号也是质数,那么就称之为质数中的质数。例如:3 5分别是排第2和第3的质数,所以他们是质数中的质数。现在给出一个数N,求>=N的最小的质数中的质数是多少?
题解:N范围是1e6,考虑用线性筛筛出1e7以下的素数,再把下标是素数的另存一个数组,二分查找答案即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

const int maxn = (int)(1e7+100);


int p[maxn], v[maxn];
int pp[maxn];
int m, t;

void pre(){
	memset(v, 0, sizeof(v));
	for(int i = 2; i <= maxn; i++){
		if(v[i] == 0){
			v[i] = i;
			p[++m] = i;
		}
		for(int j = 1; j <= m; j++){
			if(v[i] < p[j] || p[j] > maxn/i) break;
			v[i*p[j]] = p[j];
		}
	}
	for(int i = 1; i <= m; i++){
		if(v[i] == i){
			pp[++t] = p[i];
			//printf("%d ", i);
		}
	}
}

int main(){
	pre();
	int n;
	scanf("%d", &n);
	int x = lower_bound(pp+1, pp+t+1, n) - pp;
	printf("%d\n", pp[x]);
return 0;
}
 

#12. 51nod 1080
题意:给出一个整数N,将N表示为2个整数i与j的平方之和(i <= j),如果有多种表示,按照i的递增序输出。
例如:N = 130,130 = 3^2 + 11^2 = 7^2 + 92(注:32 + 112同112 + 3^2算1种)
题解:i最大sqrt(n/2),暴力枚举即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

int v[40005];

int main(){
	int n, t, flag = 1;
	memset(v, 0, sizeof(v));
	scanf("%d", &n);
	t = (int)sqrt(n/2);
	for(int i = 0; i <= t; i++){
		int x = n - i*i;
		int y = (int)sqrt(x);
		if(y*y == x && !v[y]){
			printf("%d %d\n", i, y);
			v[i] = 1;
			flag = 0;
		}
	}
	if(flag){
		printf("No Solution\n");
	}
return 0;
}

#13. 51nod 1010
题意: K的因子中只包含2 3 5。满足条件的前10个数是:2,3,4,5,6,8,9,10,12,15。
所有这样的K组成了一个序列S,现在给出一个数n,求S中 >= 给定数的最小的数。
例如:n = 13,S中 >= 13的最小的数是15,所以输出15。
题解: 预处理出1e18内的这样的数,二分查找即可。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;

const LL maxn = (LL)1e18+100LL;

int T;
LL n;
LL num[1000005], tot;

void pre(){
	tot = 0;
	for(LL i = 1; i <= maxn; i *= 2LL){
		for(LL j = 1; i*j <= maxn; j *= 3LL){
			for(LL k = 1; i*j*k <= maxn; k *= 5LL){
				if(i*j*k != 1)
					num[++tot] = i*j*k;
			}
		}
	}
	sort(num+1, num+tot+1);
}


int main(){
	pre();
	scanf("%d", &T);
	while(T--){
		scanf("%lld", &n);
		int x = lower_bound(num+1, num+1+tot, n) - num;
		printf("%lld\n", num[x]);
	}
return 0;
}

#14. 51nod 1126
**题意:**有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
给出A,B和N,求f(n)的值。
题解::矩阵快速幂,转移矩阵为 [ 0 B 1 A ] \begin{bmatrix} 0&amp;B\\1&amp;A\\ \end{bmatrix} [01BA],不过要注意负数要加mod再mod。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const int mod = 7;

int A, B, n;

void mul(int f[2], int a[2][2]){
	int c[2];
	memset(c, 0, sizeof(c));
	for(int i = 0; i < 2; i++){
		for(int j = 0; j < 2; j++){
			c[i] = ( c[i] + (long long)f[j] * a[j][i] ) % mod;
		}
	}
	memcpy(f, c, sizeof(c));
}

void mulself(int a[2][2]){
	int c[2][2];
	memset(c, 0, sizeof(c));
	for(int i = 0; i < 2; i++){
		for(int j = 0; j < 2; j++){
			for(int k = 0; k < 2; k++){
				c[i][j] = ( c[i][j] + (long long)a[i][k] * a[k][j] ) % mod;
			}
		}
	}
	memcpy(a, c, sizeof(c));
}

int main(){
	scanf("%d%d%d",&A,&B,&n);
	int f[2] = {1, 1};
	int a[2][2];
	a[0][0]= 0, a[1][0] = 1;
	a[0][1] = B, a[1][1] = A;
	n -= 1;
	for(; n; n >>= 1){
		if(n & 1) mul(f, a);
		mulself(a);
	}
	printf("%d\n", (f[0]+mod) % mod);
return 0;
}

#15. 51nod 1014
题意: X*X mod P = A,其中P为质数。给出P和A,求<=P的所有X。
**题解:**枚举x即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

#define LL long long

int main(){
	int p, a, flag = 0;
	scanf("%d%d", &p, &a);
	for(int i = 0; i <= p; i++){
		LL x = (LL)i*i;
		if(x % p == a){
			printf("%d ", i);
			flag = 1;
		}
	}
	if(!flag)
		printf("No Solution\n");
return 0;
}

#16. 51nod 1352
**题意:**给出N个固定集合{1,N},{2,N-1},{3,N-2},…,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数。提示:对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个。
题解:
1.设满足条件的是 ( t 1 , t 2 ) (t1, t2) (t1,t2), 即 ( A x , B y ) (Ax, By) (Ax,By),所以有 A x + B y = n + 1 Ax+By=n+1 Ax+By=n+1,转化为求这个方程的满足 1 &lt; = A x &lt; = n , 1 &lt; = B y &lt; = n 1&lt;=Ax&lt;=n, 1&lt;=By&lt;=n 1<=Ax<=n,1<=By<=n的解的个数。
2.先用扩展欧几里得求出 A x + B y = g c d ( A , B ) Ax+By=gcd(A, B) Ax+By=gcd(A,B)的一个解 x 0 x_0 x0,那么原方程的一个解就是 x 0 ∗ n + 1 d x_0*\frac {n+1}d x0dn+1.
3.公式变形: A x + B y = n + 1 Ax+By=n+1

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值