约素

来源:互联网 发布:淘宝店铺代码 编辑:程序博客网 时间:2024/04/20 09:04

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只有一个素因子, 素因子只能是整数, 于是得以上程序。

完。

1 0