数论——素数和反素数

素数

素数一般判定方法

bool isPrime(a) {
  if (a < 2) return 0;
  for (int i = 2; i * i <= a; ++i)
    if (a % i) return 0;
  return 1;
}

但对于long long int的数,O(√n)的复杂度还是会时间超限。

此时要用Miller-Rabin 素性测试,但也只是极为可能是素数。

复杂度O(klog3n)。

#include <iostream>
using namespace std ;
#define rd(x) (rand()%(x))
typedef unsigned long long ll;

ll pow_mod(ll a,ll b,ll r)
{
    ll ans=1,buff=a;
    while(b)
    {
        if(b&1)
            ans=(ans*buff)%r;
        buff=(buff*buff)%r;
        b>>=1;
    }
    return ans;
}

bool test(ll n,ll a,ll d)
{
    if(n==2) return true;
    if(n==a) return false;
    if(!(n&1)) return false;
    while(!(d&1)) d>>=1;
    ll t = pow_mod(a,d,n);
    while(d!=n-1&&t!=n-1&&t!=1){
        t = t*t%n;//下面介绍防止溢出的办法,对应数据量为10^18次方;
        d<<=1;
    }
    return t == n-1||(d&1)==1;//要么t能变成n-1,要么一开始t就等于1
}

bool isprime(ll n)
{
    int a[] = {2,3,5,7};//或者自己生成[2,N-1]以内的随机数rand()%(n-2)+2
    for(int i = 0; i <= 3; ++i){
        if(n==a[i]) return true;
        if(!test(n,a[i],n-1)) return false;
    }
    return true;
}
int main()
{
    int t,ans=0;
    ll N;
    for(cin >> t;t;t--){
        cin >> N;
        cout << ((isprime(N))?"Yes":"No") <<endl;
    }
}

注意:代码中longlong*longlong可能溢出,可以优化成快速乘。

反素数

定义:如果某个正整数 n满足如下条件,则称为是反素数: 任何小于 n的正数的约数个数都小于n的约数个数。

将该数进行质因子分解,我们可以得出n=p1k1p2k2...pnkn,所以因子个数为(k1+1)*(k2+1)..*(kn+1)

因为反素数的定义,可以得出反素数的两个特点

所以可以通过枚举,去确定反素数。

经典题型1:求因子数一定的最小数

题目链接: https://codeforces.com/problemset/problem/27/E

对于这种题,我么只要以因子数为 dfs 的返回条件基准,不断更新找到的最小值就可以了

#include <stdio.h>
#define ULL unsigned long long
#define INF ~0ULL
ULL p[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};

ULL ans;
ULL n;

// depth: 当前在枚举第几个素数。num: 当前因子数。
// temp: 当前因子数量为 num
// 的时候的数值。up:上一个素数的幂,这次应该小于等于这个幂次嘛
void dfs(ULL depth, ULL temp, ULL num, ULL up) {
  if (num > n || depth >= 16) return;
  if (num == n && ans > temp) {
    ans = temp;
    return;
  }
  for (int i = 1; i <= up; i++) {
    if (temp / p[depth] > ans) break;
    dfs(depth + 1, temp = temp * p[depth], num * (i + 1), i);
  }
}

int main() {
  while (scanf("%llu", &n) != EOF) {
    ans = INF;
    dfs(0, 1, 1, 64);
    printf("%llu\n", ans);
  }
  return 0;
}

经典题型2:求 n 以内因子数最多的数

题目链接http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1562

思路同上,只不过要改改 dfs 的返回条件。注意这样的题目的数据范围,我一开始用了 int,应该是溢出了,在循环里可能就出不来了就超时了。

上代码,0ms 过。注释就没必要写了上面写的很清楚了。

#include <cstdio>
#include <iostream>
#define ULL unsigned long long

int p[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
ULL n;
ULL ans, ans_num;  // ans 为 n 以内的最大反素数(会持续更新),ans_sum 为 ans
                   // 的因子数。

void dfs(int depth, ULL temp, ULL num, int up) {
  if (depth >= 16 || temp > n) return;
  if (num > ans_num) {
    ans = temp;
    ans_num = num;
  }
  if (num == ans_num && ans > temp) ans = temp;
  for (int i = 1; i <= up; i++) {
    if (temp * p[depth] > n) break;
    dfs(depth + 1, temp *= p[depth], num * (i + 1), i);
  }
  return;
}

int main() {
  while (scanf("%llu", &n) != EOF) {
    ans_num = 0;
    dfs(0, 1, 1, 60);
    printf("%llu\n", ans);
  }
  return 0;
}

两个题目都是利用n=p1k1p2k2...pnkn,所以因子个数为(k1+1)*(k2+1)..*(kn+1)这一性质进行枚举。

原文地址:https://www.cnblogs.com/2462478392Lee/p/12364294.html

时间: 2024-11-01 20:22:56

数论——素数和反素数的相关文章

51nod 1060 最复杂的数 反素数

1060 最复杂的数 基准时间限制:1 秒 空间限制:131072 KB 把一个数的约数个数定义为该数的复杂程度,给出一个n,求1-n中复杂程度最高的那个数. 例如:12的约数为:1 2 3 4 6 12,共6个数,所以12的复杂程度是6.如果有多个数复杂度相等,输出最小的. Input 第1行:一个数T,表示后面用作输入测试的数的数量.(1 <= T <= 100) 第2 - T + 1行:T个数,表示需要计算的n.(1 <= n <= 10^18) Output 共T行,每行2

zoj2562:搜索+数论(反素数)

题目大意:求n以内因子数量最多的数  n的范围为1e16 其实相当于求n以内最大的反素数... 由素数中的 算数基本原理 设d(a)为a的正因子的个数,则 d(n)=(a1+1)(a2+1).....*(an+1); 又由反素数的性质2: p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=.... 我们可以指定搜索策略和剪枝 详见代码和注释 #include <iostream> #include<stdio.h> #include&

BZOJ1053 [HAOI2007]反素数ant 数论

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 传送门 - BZOJ1053 题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4.如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6等都是反质数.现在给定一个数N,你能求出不超过N的最大的反质数么? (1<=N<=2,000,000,000) 题解 对于任何一个反素数p,总有: p=2q1×3q2×5q3×7q4... 而且q

51nod 1060 最复杂的数(数论,反素数)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1060 题解:可以去学习一下反素数. #include <iostream> #include <cstring> #define inf 1000000000000000007 using namespace std; typedef unsigned long long ull; const int M = 1e6 + 10; ull n ,

[BZOJ 1053] [HAOI 2007]反素数ant

1053: [HAOI2007]反素数ant Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1857  Solved: 1034[Submit][Status][Discuss] Description 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4.如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6等都是反质数.现在给定一个数N,你能求出不超过N的最大的反质数么?

HDU 2521 反素数

反素数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4238    Accepted Submission(s): 2456 Problem Description 反素数就是满足对于任意i(0<i<x),都有g(i)<g(x),(g(x)是x的因子个数),则x为一个反素数.现在给你一个整数区间[a,b],请你求出该区间的x使

洛谷 P1463 [SDOI2005]反素数ant

P1463 [SDOI2005]反素数ant 题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6等都是反质数. 现在给定一个数N,你能求出不超过N的最大的反质数么? 输入输出格式 输入格式: 一个数N(1<=N<=2,000,000,000). 输出格式: 不超过N的最大的反质数. 输入输出样例 输入样例#1: 1000 输出样例#1: 840思

luoguP1463 [HAOI2007]反素数

题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6等都是反质数. 现在给定一个数N,你能求出不超过N的最大的反质数么? 输入输出格式 输入格式: 一个数N(1<=N<=2,000,000,000). 输出格式: 不超过N的最大的反质数. 输入输出样例 输入样例#1: 复制 1000 输出样例#1: 复制840 思路:一看这道题,不用说这是个数论,

反素数 -- 数学

反素数就是区间内约数个数最多的那个数. 在ACM题目里, 一般是求约数最多而且数字最小的那个数,[1--n] 二是求约数刚好等于n的最小的那个数 三是求区间里的最小反素数[beign,end] 1和3有区别吗?有,1可以加速,3只能暴力 先说下思路 思路 : 官方题解 : (1)此题最容易想到的是穷举,但是肯定超时. (2)我们可以知道,计算约数的个数和质因数分解有着很大的联系: 若Q的质因数分解为:Q=p1^k1*p2^k2*…*pm^km(p1…pm为素数,k1…km≥1),则Q有(k1+1