约素

http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4274
4274: 约素
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 1890 Solved: 493
Description
判断一个正整数n的约数个数是否为p,其中p是素数。
Input
第一行给测试总数T(T <= 10000)。
接下来有T行,每行有两个数字n(1 <= n <= 1000000000)和p(2 < p <= 1000000000)。
Output
每组测试数据输出一行,如果n的约数个数是p,输出“YES”,否则输出“NO”。
Sample Input
5
64 7
911 233
1080 13
1024 11
20170211 1913
Sample Output
YES
NO
NO
YES
NO

题意很清楚, 无需多说什么。
我给出三种解法:

第一种:超时的。(数据组数太多)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
int n, p;
int main()
{
    int t;
    for (scanf("%d", &t); t; t--){
        scanf("%d%d", &n, &p);
        int cnt=1;
        for (LL i=2; i*i<=n; i++){
            if (n%i==0){//找到一个素因子
                int num=0;
                while (n%i==0) {
                    num++;
                    n/=i;
                }
                cnt*=(1+num);//算术基本定理的结论
            }
        }
        if (n!=1){
            cnt*=2;//必不可少
        }
        if (cnt!=p)  printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}
第二种:(预处理, 时间复杂度是没有问题的, 但是还是超时了,因为程序有错)
首先给出一个错误的程序:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
int N, P;
const LL maxn=1e6;
bool prime[maxn];
LL p[maxn];
LL cn;
void cnt_prime()
{
    cn=0;
    memset(prime, 0, sizeof prime);
    for (LL i=2; i<maxn; i++){
        if (!prime[i]){
            p[cn++]=i;if (cn==1)
            for (LL j=i*i; j<=maxn; j+=i) {//这里出现了一个不那么显然的错误, 一不小心就gg了
                prime[j]=true;
            }
        }
    }
}
int main()
{
    int t;
    cnt_prime();cout<<p[0]<<endl;
    for (scanf("%d", &t); t; t--){
        scanf("%d%d", &N, &P);
        LL cnt=1;
        for (LL i=0; i<cn && p[i]*p[i]<=N; i++){
            if (N%p[i]==0){
                LL num=0;
                while (N%p[i]==0) {
                    num++;
                    N=N/p[i];
                }
                cnt*=(1+num);
            }
        }
        if (N>1){
            cnt*=2;
        }
        if (cnt!=P)  printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

上面这个程序会导致超时, 经过多次测试, 我发现了p[0]==1!!!! 是的, 其它的素数都对了, 但第一个素数应该是2。想不到原因啊!(临时把p[0]强制赋值为2当然是可以AC了, 但是为什么会出现p[0]==1呢?)很无奈, 问了别人, 也是看不出来。好吧,最终还是硬着头皮一句一句分析找原因, 原来是“j<=maxn”这里考虑不周:当j==maxn时, prime[maxn]=true; 也就是p[0]=true=1! Orz…因为prime的下标只能去到maxn-1, 所以prime[maxn]对应的地址就是p[0]的地址。这种问题, 我以前给别人看程序的时候出现过一次, 也是花了很多时间才找出来的。 没想到这次再次出现了还是不能一眼察觉。。。还是不够细心严谨啊, 这就是教训!所以把“j<=maxn” 中的等号去掉即可AC。

第三种方法:(应该是最高效的了吧)
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
const double eps=1e-8;
typedef long long LL;
bool is_prime(int x)
{
    if (x<2) return false;
    if (x==2 || x==3) return true;
    for (LL i=2; i*i<=x; i++){
        if (x%i==0) return false;
    }
    return true;
}
int main()
{
    int t;
    for (scanf("%d", &t); t; t--){
        int n, p;
        scanf("%d%d", &n, &p);
        int x=pow(n+0.5, 1.0/(p-1));//p是素数,=> n只有一个素因子x,=> p=(1+p-1); => x^(p-1)==n
        if (fabs(pow(x, p-1)-n)<eps && is_prime(x)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

第三个程序成立的必要条件是p是素数, 这个是题目给的。 若n=p0^e0 + p1^e1 + … + pi^ei;
则p=(1+e0)* (1+e1) * … *(1+ei) => p只有一个素因子, 素因子只能是整数, 于是得以上程序。

完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值