关闭

poj 3361 Gaussian Prime Factors 高斯素数约数

标签: ACMmath素数高斯素数
248人阅读 评论(0) 收藏 举报
分类:

poj 3361 Gaussian Prime Factors

题意:

在复数 a+bj (a,b为整数)范围内,约数只有 1, -1, a+bj, -(a+bj)的称为高斯素数。求任给正整数N的所有素因子(|b|>a>0)。默认N<2e9

解法:

定理有云:
n≡3(mod 4)者,无因式分解。
n≡1(mod 4)者,可唯一分解为两个共轭高斯整数乘积。

当然做的时候并不知道!
我的思路是,既然可以分解因子,那么可以先分解成素因子,再把素因子分解出来。发现3,7等数是不能分解的,其他的素数(忽略2)都是奇数,要分解成乘积,最后不能有虚部存在,故得分解成共轭高斯整数相乘,即(a+bj)(a-bj)=n,即 a^2+b^2 = n,则a,b一奇一偶。且因为若a+bj不为素数,则可分解为 (c+dj)(e+fj),那么(a+bj)(a-bj)=(c+dj)(c-dj)(e+fj)(e-fj)=n,此时前两项与后两项都为一个实整数,与n为素数矛盾,故只要分解出来,a+bj与a-bj则一定为n的素因子。
这样就好办了,对所有的N,都先进行素因子分解,然后对每个素因子再分解其高斯素因子。我选择遍历a,b来预处理出所有素数的标准因子a+bj(另一个则为a-bj)。

自己的坑:
低估了45000内素数数量,大约为十分之一个。
使用了set,但是貌似不是这么用的。(我用来验证m-i^2是否为完全平方数,多了一个log(num_pri)的复杂度)。应该是直接检验比较快。

so,学到了STL set:

myset.count(n)  ->得到数量
myset.insert(n) ->插入
myset.find(n)   ->得到迭代器,找不到则是末尾。 .erase(.find(n))

140+行代码,500+ms过。可能是预处理和数据结构比较费时间。看别人的当场暴力分解质因数,暴力分解素数的0ms过。只能说数据太水太水啦!~

我的代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 45000;
const int maxq = 212;
struct stt{
    int a,b;
}q[maxn],tmpst;
vector <stt> ans;
set <int> myset;
int prim[5000];
bool isnotpri[maxn];
int prinum = 0;
int prime,sise;
int sq[maxq+1];//square

void ini(){
    memset(prim,0,sizeof prim);
    memset(isnotpri,false,sizeof isnotpri);
    memset(q,0,sizeof q);
    myset.clear();
    //memset(ans,0,sizeof ans);
    ans.clear();
    for(int i = 2; i <= maxq; i++){
        if(!isnotpri[i]){
            for(int j = i*i; j < maxn; j += i){
                isnotpri[j] = 1;
            }
        }
    }
    for(int i = 2; i <= maxn; i++){
        if(!isnotpri[i]) prim[prinum++]=i;
    }
    q[2].a=1;
    q[2].b=1;
    for(int i = 1; i <= maxq; i++){
        sq[i] = i*i;
    }
    int tmp;
    for(int i = 1; i <= maxq; i++){
        for(int j = i+1; j <= maxq; j += 2){
            tmp = sq[i]+sq[j];
            if(tmp >= maxn) break;
            if(!isnotpri[tmp]){
                q[tmp].a = i;
                q[tmp].b = j;
            }
        }
    }
    for(int i = 2; i <= maxn; i++){
        if(q[i].b == 0) q[i].a = i;
        myset.insert(i*i);
    }
}
void gener(int m){
    ans.clear();
    if(m == 0 || m == 1) return;
    for(int i = 0; i < prinum; i++){
        prime = prim[i];
        if(prime > m) break;
        if(m % prime == 0){
            ans.push_back(q[prime]);
            while(m % prime == 0){
                m /= prime;
            }
        }
    }
    if(m != 1){
        if(m%4==3){
            tmpst.a = m;
            tmpst.b = 0;
            ans.push_back(tmpst);
        }
        else{
            int tmp = (int)sqrt(m+0.1);
            int tmp2;
            for(int i = 1; i <= tmp; i++){
                if(myset.count(m-i*i)!=0){
                    tmpst.a = i;
                    tmpst.b = (int)sqrt(m-i*i+0.1);
                    ans.push_back(tmpst);
                    break;
                }
            }
        }
    }
}
bool cmp(stt i, stt j){
    if(i.a == j.a){
        return i.b < j.b;
    }
    return i.a < j.a;
}
void printout(){
    sise = ans.size();
    if(sise == 0){
        printf("\n");
        return;
    }
    sort(ans.begin(),ans.end(),cmp);
    int aa,bb;
    for(int i = 0; i < sise; i++){
        aa = ans[i].a, bb = ans[i].b;
        if(bb==0){
            printf(" %d",aa);
        }
        else{
            if(bb==1){
                printf(" %d+j, %d-j",aa,aa);
            }
            else{
                printf(" %d+%dj, %d-%dj",aa,bb,aa,bb);
            }

        }
        printf("%c",",\n"[i==sise-1]);
    }
}
int main(){
    freopen("in.txt","r",stdin);
    ini();
    int k = 1;
    int m;
    //return 0;
    while(scanf("%d",&m)!=EOF){
        printf("Case #%d:",k++);
        gener(m);
        printout();
    }
    return 0;
}

别人的代码:

from yjCola

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1005
struct ele
{
    int a,b;
    bool operator < (const ele &c) const
    {
        if(a==c.a)
        {
            if(abs(b)==abs(c.b))
                return b>c.b;
            else
                return abs(b)<abs(c.b);
        }
        else
            return a<c.a;
    }
}e[MAXN];
int up;
void get(int p)
{
    if((p-3)%4==0) e[up].a=p,e[up++].b=0;
    else
    {
        for(int i=1;i*i<=p;i++)
        {
            int j=sqrt(1.0*(p-i*i));
            if(i*i+j*j==p)
            {
                e[up].a=i,e[up++].b=j;
                e[up].a=i,e[up++].b=-j;
                break;
            }
        }
    }
}
int main()
{
    int cas=1,n;
    while(scanf("%d",&n)!=EOF)
    {
        up=0;
        for(int i=2;i*i<=n;i++)
            if(n%i==0)
            {
                get(i);
                while(n%i==0) n/=i;
            }
        if(n>1) get(n);
        sort(e,e+up);
        printf("Case #%d:",cas++);
        for(int i=0;i<up;i++)
        {
            printf(" %d",e[i].a);
            if(e[i].b<0)
            {
                if(e[i].b==-1) printf("-j");
                else printf("%dj",e[i].b);
            }
            else if(e[i].b>0)
            {
                if(e[i].b==1) printf("+j");
                else printf("+%dj",e[i].b);
            }
            if(i<up-1) printf(",");
        }
        printf("\n");
    }
    return 0;
}

疑问:

看到有个人说 1 = j·(-j),为何1不是素因子,想想如果酱紫的话,j = 1·j, 所有的单位元都可以认为是素因子了。思考了下,可能是因为,由于a+bj和 j*(a+bj)是等价的因子,所以1 = j·(-j)又可以认为是1=1·(-1),1与本身重合,所以 1 仍是作为单元,而非素因子。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1618次
    • 积分:91
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:2篇
    • 译文:0篇
    • 评论:1条
    文章分类
    最新评论