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

#查找某篇题解:ctrl+f

#1 .51nod 1011

gcd,不解释

代码:

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

#2 .51nod 1135

求最小原根

代码:

#include 
#include 
#include 
#include 
#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 
#include 
#include 
#include 
#include 

#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 

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<

#5. 51nod 1256

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

代码:

#include 
#include 
#include 
#include 
#include 

#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 
#include 

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<

#7 .51nod 1079

中国剩余定理

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

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

代码:

#include 
#include 
#include 
#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 
#include 
#include 
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 
#include 
#include 
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 
#include 
#include 
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 
#include 
#include 
#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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#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&B\\1&A\\ \end{bmatrix} [01BA],不过要注意负数要加mod再mod。

#include 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 

#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 < = A x < = n , 1 < = B y < = n 1<=Ax<=n, 1<=By<=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 Ax+By=n+1 => A ( x + t ∗ B g c d ( A , B ) ) + B ( y − t ∗ A g c d ( A , B ) ) = n + 1 A(x+t*\frac {B}{gcd(A,B)}) + B(y - t*\frac{A}{gcd(A,B)}) = n+1 A(x+tgcd(A,B)B)+B(ytgcd(A,B)A)=n+1
4.所以当 x x x 增加 B g c d ( A , B ) \frac{B}{gcd(A,B)} gcd(A,B)B时, y y y相应的减少 A g c d ( A , B ) \frac{A}{gcd(A,B)} gcd(A,B)A.然后计数在 1 ∼ n 1\sim n 1n的即可。

#include 
#include 
#include 

#define LL long long

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

int main(){
	int t;
	LL n, a, b;
	scanf("%d", &t);
	while(t--){
		LL d, x0, y0;
		scanf("%lld%lld%lld", &n, &a, &b);
		d = exgcd(a, b, x0, y0);
		if((n+1) % d){
			printf("0\n");
			continue;
		}
		LL dt = b/d;
		//printf("x00:%d\n", x0);
		x0 *= (n+1)/d;
		x0 %= dt;
		while(x0 <= 0) x0 += b/d;
		//printf("x0:%d\n", x0);
		LL tmp = n - x0*a;
		if(tmp < 0){
			printf("0\n");
			continue;
		}
		LL lc = a*b/d;
		printf("%lld\n", 1+tmp/lc);
	}
}

#17. 51nod 1247
**题意:**在一个无限大的二维网格上,你站在(a,b)点上,下一步你可以移动到(a + b, b), (a, a + b), (a - b, b), 或者 (a, a - b)这4个点。给出起点坐标(a,b),以及终点坐标(x,y),问你能否从起点移动到终点。如果可以,输出"Yes",否则输出"No"。例如:(1,1) 到 (2,3),(1,1) -> (2,1) -> (2,3)。
**题解:**只需判断是否能到达即可,所以考虑这两对数之间肯定有相同的地方,很自然的会想到最大公约数。
那么为什么是最大公约数呢,首先变化是可逆的,题目给的操作要么两数之和,要么两数之差,这两个是可逆的。其次,就是从更相减损术来的,题目的操作其实就是更相减损术的流程。

#include 
#include 

#define LL long long

using namespace std;

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

int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		LL a, b, c, d;
		scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
		if(gcd(a, b) == gcd(c, d))
			printf("Yes\n");
		else printf("No\n");
	}
return 0;
}

#18. 51nod 1035
**题意:**正整数k的倒数1/k,写为10进制的小数如果为无限循环小数,则存在一个循环节,求<=n的数中,倒数循环节长度最长的那个数,假如存在多个最优的答案,输出所有答案中最大的那个数。1/6= 0.1(6) 循环节长度为11/7= 0.(142857) 循环节长度为61/9= 0.(1) 循环节长度为1
**题解:**建议阅读:http://w3.math.sinica.edu.tw/math_media/d253/25311.pdf

#include 
#include 
#include 
#include 
#define LL long long

using namespace std;

int phi[1005]; 

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

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

void Phi(int n){
	for(int i = 2; i <= n; i++) phi[i] = i;
	for(int i = 2; i <= n; i++){
		if(phi[i] == i){
			for(int j = i; j <= n; j += i){
				phi[j] = phi[j]/i*(i-1);
			}
		}
	}
}	

int main(){
	int n, res = 0, len = 0;
	scanf("%d", &n);
	Phi(n);
	for(int i = 2; i <= n; i++){
		if(gcd(10, i) != 1)
			continue;
		int t = phi[i];
		for(int j = 1; j <= t; j++){
			if(t % j == 0 && Pow(10, j, i) == 1){
				if(j > len){
					len = j;
					res = i;
				}
				break;
			}
		}
	}
	printf("%d\n", res);
return 0;
}

#19. 51nod 1116
题意: 有一个字符串S,记录了一个大数,但不知这个大数是多少进制的,只知道这个数在K进制下是K - 1的倍数。现在由你来求出这个最小的进制K。例如:给出的数是A1A,有A则最少也是11进制,然后发现A1A在22进制下等于4872,4872 mod 21 = 0,并且22是最小的,因此输出k = 22(大数的表示中A对应10,Z对应35)。
**题解:**设这个数的K进制表示为 a n ∗ K n − 1 + a n − 1 ∗ K n − 2 + ⋯ + a 2 ∗ K + a 1 a_n*K^{n-1}+a_{n-1}*K^{n-2}+\dots+a_2*K+a_1 anKn1+an1Kn2++a2K+a1
由公式 x n − 1 = ( x − 1 ) ( 1 + x + x 2 + ⋯ + x n − 1 ) x^n-1=(x-1)(1+x+x^2+\dots+x^{n-1}) xn1=(x1)(1+x+x2++xn1)。对上式中的每一项
a i ∗ K i − 1 = a i ∗ ( ( K − 1 ) ( 1 + ⋯ + K i − 1 ) + 1 ) = a i ∗ ( K − 1 ) ( 1 + ⋯ + K i − 1 ) + a i a_i*K^{i-1}=a_i*\biggr ((K-1)(1+\dots+K^{i-1})+1 \biggr)=a_i*(K-1)(1+\dots+K^{i-1})+a_i aiKi1=ai((K1)(1++Ki1)+1)=ai(K1)(1++Ki1)+ai
通过上式不难发现,第一项是能被 K − 1 K-1 K1整除的,所以只要所有系数之和能被 K − 1 K-1 K1整除,这个数也就能被 K − 1 K-1 K1整除。

#include 
#include 
#include 
#include 
#include 
#define LL long long

using namespace std;

char s[100005];
int t[1000005];
LL ans = 0;

int main(){
	int ma = -1;
	scanf("%s", s);
	int len = strlen(s);
	for(int i = 0; i < len; i++){
		if(s[i] >= '0' && s[i] <= '9')
			t[i] = s[i] - 48;
		if(s[i] >= 'A' && s[i] <= 'Z')
			t[i] = s[i] - 65 + 10;
		ma = max(ma, t[i]+1);
		ans += t[i];
	}
	for(int i = ma; i <= 36; i++){
		if(ans % (i-1) == 0){
			printf("%d\n", i);
			return 0;
		}
	}
	printf("No Solution\n");
return 0;
}

#20. 51nod 1179
题意:给出N个正整数,找出N个数两两之间最大公约数的最大值。例如:N = 4,4个数为:9 15 25 16,两两之间最大公约数的最大值是15同25的最大公约数5。
题解:暴力枚举每个数的因数,用一个桶记录因数$\ i\ $的出现次数。再从max(a[i])往下扫,第一个出现次数大于等于2的就是答案。

#include 
#include 
#include 

using namespace std;

int max(int a, int b){
	return a > b ? a : b;
}

int n;
int a[50005], cnt[1000005];
int Max;

int main(){
	Max = -1;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
		Max = max(a[i], Max);
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j*j <= a[i]; j++){
			if(a[i] % j == 0){
				cnt[j]++;
				cnt[a[i]/j]++;
			}
		}
	}
	for(int i = Max; i >= 1; i--){
		if(cnt[i] >= 2){
			printf("%d\n", i);
			break;
		}
	}
return 0;
} 

#21. 51nod 1434
题意:现在给定一个整数N(1<=N<=1000000),需要找到一个整数M,满足M>N,同时LCM(1,2,3,4,…,N-1,N) 整除 LCM(N+1,N+2,…,M-1,M),即LCM(N+1,N+2,…,M-1,M)是LCM(1,2,3,4,…,N-1,N) 的倍数.求最小的M值。
题解:考虑 L C M ( 1 , 2 , . . . , N ) LCM(1,2,...,N) LCM(1,2,...,N) L C M ( N + 1 , . . . M ) LCM(N+1, ...M) LCM(N+1,...M)的质因数分解形式,易知大于 N N N的质数不用考虑,只用考虑 1 ∼ N 1\sim N 1N的质数。对于质数 P P P, 求出一个刚好满足 P t < = N P^t <= N Pt<=N t t t, 再找到一个系数 C C C使得 C ∗ P t > N C*P^t>N CPt>N,所有满足条件中最大的就是M的值。

#include 
#include 
#include 
#include 
#include 
#define LL long long
#define mem(a, b) memset(a, b, sizeof(a))
const int maxn = 1000005;

int cnt[maxn];
int p[maxn], v[maxn];
int tot = 0;

int max(int a, int b){
	return a > b ? a : b;
}

void prime(int n){
	mem(v, 0);
	tot = 0;
	for(int i = 2; i <= n; i++){
		if(!v[i]){
			v[i] = i;
			p[++tot] = i;
		}
		for(int j = 1; j <= tot; j++){
			if(v[i] < p[j] || p[j] > n/i) break;
			v[i*p[j]] = p[j];
		}
	}
}

int T;

int main(){
	prime(1000003);
	scanf("%d", &T);
	while(T--){
		int n, ans = 2;
		scanf("%d", &n);
		for(int i = 2; i <= n; i++){
			if(v[i] == i){
				int k = 1;
				while(k <= n/i){
					k *= i;
				}
				for(int j = 2; ; j++){
					if(k * j > n){
						k *= j;
						break;
					}
				}
				ans = max(ans, k);
			}
		}
		printf("%d\n", ans);
	}
return 0;
} 

#22. 51nod 1186

Miller_Robbin 素性检测

为避免C++的高精度,用python编写

import random

def rand(l, r):
    return int((r - l + 1) * random.random() + l)

def qpow(a, x, P):
    ret = 1
    while(x):
        if(x & 1):
            ret = ret * a % P
        a = a * a % P
        x >>= 1
    return ret

def witness(a, n):
    t = 0
    u = n - 1;
    while(not(u & 1)):
        t += 1
        u >>= 1
    last = qpow(a, u, n)
    for i in range(0, t):
        cur = last * last % n
        if(cur == 1 and last != 1 and last != n - 1):
            return 1
        last = cur
    return (last != 1)

def miller_rabin(n, s):
    if(n == 2):
        return 1
    for i in range(0, s):
        a = rand(2, n - 1)
        if witness(a, n):
            return 0
        return 1

n = int(input())

if(miller_rabin(n, 20)):
    print("Yes")
else:
    print("No")

#23. 51nod 1060
题意:
把一个数的约数个数定义为该数的复杂程度,给出一个n,求1-n中复杂程度最高的那个数。
例如:12的约数为:1 2 3 4 6 12,共6个数,所以12的复杂程度是6。如果有多个数复杂度相等,输出最小的。
题解:
1.题目所求就是反素数(自行百度)
2.由于N的范围(1e18),1-N的数不同质因子个数不超过16,因为这16个质因子乘起来就大于1e18了。而且所有质因子的指数和不会很大。
3.x是反素数的必要条件是它的质因子由若干个连续的最小的质数构成,且质数单调递减。
因为若不是这样,则可以通过交换质因子的方法得到一个比x小,但约数个数相等的数。
其他:与BZOJ 1035类似

#include 
#include 
#include 
#include 
#include  
using namespace std;
#define LL long long	

const int prime[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
LL n;
LL ans = 1, ans_num = 1;

void dfs(int now, LL mul, LL num, LL last){
	if(now >= 16) 
		return; 
	else{
		if(num > ans_num){
			ans_num = num;
			ans = mul;
		}
		else if(num == ans_num){
			ans = min(mul, ans);
		}
		LL i;
		for(i = 1; i <= last; i++){
			if(mul <= n/prime[now]){
				mul *= prime[now];
				dfs(now+1, mul, num*(i+1), i);
			}
			else
				break;
		}
	}
}


int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		ans = ans_num = 1;
		scanf("%lld", &n);
		dfs(0, 1, 1, 15);
		printf("%lld %lld\n", ans, ans_num);
	}
return 0;	
}

#24. 51nod 1341
##题意:
给出两个数列 a n , b n a_n,b_n an,bn ( ∑ i = 0 n a i b n − i ) % ( 1 e 9 + 7 ) (\sum_{i=0}^n{a_ib_{n-i}})\%(1e9+7) (i=0naibni)%(1e9+7)
##题解:
c n = a 0 b n + a 1 b n − 1 + ⋯ + a n b 0 c_n=a_0b_n+a_1b_{n-1}+\dots+a_nb_0 cn=a0bn+a1bn1++anb0
c n + 1 = a 0 b n + 1 + a 1 b n + ⋯ + a n b 1 + a n + 1 b 0 c_{n+1}=a_0b_{n+1}+a_1b_n+\dots+a_nb_1+a_{n+1}b_0 cn+1=a0bn+1+a1bn++anb1+an+1b0
观察可得: c n + 1 = q c n + a n + 1 b 0 c_{n+1}=qc_n+a_{n+1}b_0 cn+1=qcn+an+1b0
于是构建矩阵 A = ( q 0 0 b 0 ∗ q p 0 b 0 1 1 ) A=\begin{pmatrix} q&0&0\\b_0*q&p&0\\b_0&1&1 \end{pmatrix} A=qb0qb00p1001使得 [ c n + 1 a n + 1 r ] = [ c n a n r ] ( q 0 0 b 0 ∗ q p 0 b 0 1 1 ) \begin{bmatrix} c_{n+1} \quad a_{n+1}\quad r\end{bmatrix}= \begin{bmatrix} c_n\quad a_n \quad r\end{bmatrix} \begin{pmatrix} q&0&0\\b_0*q&p&0\\b_0&1&1 \end{pmatrix} [cn+1an+1r]=[cnanr]qb0qb00p1001
于是 [ c n a n r ] = [ c 0 a 0 r ] A n \begin{bmatrix} c_n\quad a_n \quad r\end{bmatrix}= \begin{bmatrix} c_0\quad a_0 \quad r\end{bmatrix}A^n [cnanr]=[c0a0r]An
可得 c n = r ∗ A n c_n=r*A^n cn=rAn
矩阵快速幂可解决。
##代码:

#include 
#include 
#include 
#include 
#include 
#define LL long long

const int MOD = 1000000007;

struct Mat{
	LL ma[3][3];
};

Mat mul(Mat a, Mat b){
		Mat c;
		for(int i = 0; i < 3; i++){
			for(int j = 0; j < 3; j++){
				c.ma[i][j] = 0;
				for(int k = 0; k < 3; k++){
					c.ma[i][j] = c.ma[i][j] + a.ma[i][k]*b.ma[k][j]%MOD;
					c.ma[i][j] = (c.ma[i][j]%MOD+MOD)%MOD;
				}
			}
		}
		return c;
	}
	
	Mat pow(Mat a, LL b){
		Mat ans;
		memset(ans.ma, 0, sizeof(ans.ma));
		for(int i = 0; i < 3; i++){
			ans.ma[i][i] = 1;
		}
		while(b){
			if(b & 1)
				ans = mul(ans, a);
			b >>= 1;
			a = mul(a, a);
		}
		return ans;
	}

int main(){
	LL p,q,r,n;
	scanf("%lld%lld%lld%lld", &p, &q, &r, &n);
	Mat x;
	x.ma[0][0] = q, x.ma[0][1] = 0, x.ma[0][2] = 0;
	x.ma[1][0] = 3*p%MOD, x.ma[1][1] = p, x.ma[1][2] = 0;
	x.ma[2][0] = 3, x.ma[2][1] = 1, x.ma[2][2] = 1;
	x = pow(x, n);
	LL ans = (x.ma[2][0]*r%MOD+MOD)%MOD;
	printf("%lld\n", ans);
return 0;
}

#25. 51nod 1189(待写)
#25. 51nod 1262(待写)

你可能感兴趣的:(51nod)