信安数学基础编程题

整除

Eratosthenes筛选法求素数

const int range=1000000; //求素数的范围
int *p=new int[range+1]; //存储该范围内所有数的数组

void eratosthenes(int *p) { //Eratosthenes筛选法
    for(int i=2;i<=ceil(sqrt(range));i++)
        for(int j=2*i;j<=range;j+=i) //将i的倍数都赋成0
            p[j]=0;
}

int main() {
    for(int i=0;i<=range;i++) //初始化数组
        p[i]=i;
    p[1]=0;
    eratosthenes(p);
    int count=0;
    for(int i=2;i<=range;i++) { //遍历数组
        if(p[i]!=0) { //输出不为0的数(即素数)
            cout<<p[i]<<" ";
            count++;
            if(count%5==0) //5个一行
                cout<<endl;
        }
    }
    return 0;
}

辗转相除法求最大公因子

int gcd(int a,int b) { //辗转相除法
    if(a<b) //a为大的那个数
        swap(a, b);
    int r=a%b; //余数
    while(r!=0) { //当余数不为0时
        a=b;
        b=r;
        r=a%b;
    }
    return b;
}

求素因子分解

void deposition(int n) { //求素因子分解
    for(int i=2;i<=n;i++) { //遍历
        int count=0; //次幂
        while(n%i==0) { //如果能整除
            count++; //次数+1
            n/=i; //除掉因子
        }
        if(count!=0) { //输出分解式
            cout<<i;
            if(count!=1)
                cout<<"^"<<count;
            if(n!=1)
                cout<<"×";
            else break;
        }
    }
}

同余

求正整数的欧拉函数

//只要稍微改动一下求素因子分解的函数即可

int euler=1; //欧拉函数
euler*=(1-1/double(i)); //计算欧拉函数,i为素因子

拓展欧几里得算法求乘法逆元

int inverse(int x,int y) { //求x模y的乘法逆元
    int flag=0; //记录是否交换x,y
    if(x<y) { //令x为较大的那一个
        flag=1;
        swap(x, y);
    }
    //以下利用扩展欧几里得算法求乘法逆元
    int count=1, s[100], t[100], r[100], q[100];
    r[0]=x;
    r[1]=y;
    s[0]=t[1]=1;
    s[1]=t[0]=0;
    while(r[count]!=0) { //当余数不为0时
       q[count]=r[count-1]/r[count];
       s[count+1]=s[count-1]-q[count]*s[count];
       t[count+1]=t[count-1]-q[count]*t[count];
       count++;
       r[count]=r[count-2]%r[count-1];
   }
   if(flag==1) {
       if(t[count-1]<0)
           return t[count-1]+x;
       else
           return t[count-1];
   }
   else {
       if(s[count-1]<0)
           return s[count-1]+y;
       else
           return s[count-1];
   }
}

实现中国剩余定理

int main() {
    int n; //同余方程的个数
    cin>>n; //以下利用中国剩余定理求同余方程组的解
    int *b=new int[n],
        *m=new int[n],
        *a=new int[n], *a_inverse=new int[n];
    int mul=1; //模的数的乘积
    for(int i=0;i<n;i++) {
       cin>>b[i]>>m[i];
        mul*=m[i];
    }
    for(int i=0;i<n;i++) {
        a[i]=1;
        for(int j=0;j<n;j++) {
            if(j==i)
                continue;
            a[i]*=m[j];
        }
        a_inverse[i]=inverse(a[i],m[i]); //求乘法逆元
    }
    int result=0;
    for(int i=0;i<n;i++)
        result+=a_inverse[i]*a[i]*b[i];
    result%=mul;
    cout<<"x="<<result<<" (mod "<<mul<<")"<<endl;
    return 0;
}

原根和指数

求奇素数原根

//改写求素因子分解的函数,使其记录素因子,并返回素因子个数

int reduceSystem(int n, int *p) { //求缩系
    int count=0; //缩系元素个数
    for(int i=1;i<n;i++) {
        if(gcd(i, n)==1) { //如果互素
            p[count]=i;
            count++;
        }
    }
    return count;
}

int remain(int a, int n, int m) { //求余数
    int r=a%m;
    for(int i=1;i<n;i++)
        r=(r*a)%m; //依次求余数,而不是直接求余数,避免溢出
    return r;
}

int primaryRoot(int m) { //求最小原根
    int o=m-1, //欧拉函数
        *p=new int[m]; //欧拉函数的素因子
    int len=deposition(o, p); //欧拉函数的素因子个数
    for(int i=0;i<len;i++)
        p[i]=(o/p[i]);
    int root=0; //最小原根
    for(int i=2;i<m;i++) {
        int flag=true; //是否为原根
        for(int j=0;j<len;j++) {
            if(remain(i,p[j],m)==1) { //与1同余
                flag=false; //不是原根
                break;
            }
        }
        if(flag) {
            root=i;
            break; //找到最小原根
        }
    }
    return root;
}

int main() {
    int m; //奇素数
    cin>>m;
    int *r=new int[m-1]; //欧拉函数的缩系
    int len=reduceSystem(m-1, r); //欧拉函数缩系的长度
    int *result=new int[len]; //奇素数的所有原根
    for(int i=0;i<len;i++)
        result[i]=remain(primaryRoot(m), r[i], m);
    sort(result,result+len); //按照从小到大的顺序排列
    for(int i=0;i<len;i++)
        cout<<result[i]<<" ";
    cout<<endl;
    return 0;
}

构造指数表

void index(int m) { //求指数表,m为奇素数
    int root=primaryRoot(m), o=m-1;
    int *ind=new int[o]; //指数
    ind[0]=1;
    for(int i=1;i<o;i++)
        ind[i]=remain(root, i, o+1);
    int **table=new int*[o/10+1]; //指数表
    for(int i=0;i<o/10+1;i++)
        table[i]=new int[10];
    for(int i=0;i<o/10+1;i++)
        for(int j=0;j<10;j++)
            table[i][j]=-1; //初始化为-1
    for(int i=0;i<o;i++) { //入表
        int a=ind[i]/10;
        int b=ind[i]%10;
        table[a][b]=i;
    }
    //以下是输出格式设置
    cout<<setw(5)<<" ";
    for(int i=0;i<10;i++)
        cout<<setw(5)<<i;
    cout<<endl;
    for(int i=0;i<o/10+1;i++){
        cout<<setw(5)<<i;
        for(int j=0;j<10;j++){
            if(table[i][j]==-1)
                cout<<setw(5)<<" ";
            else
                cout<<setw(5)<<table[i][j];
        }
        cout<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值