程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 數論中的基本算法 POJ 1845 SPOJ DIVSUM

數論中的基本算法 POJ 1845 SPOJ DIVSUM

編輯:C++入門知識

擴展歐幾裡得 求逆元(只要a與b互素,那麼就有逆元)
[cpp] 
#include<cstdio> 
#include<cstring> 
#include<cstdlib> 
#include<cmath> 
#define mod 9973 
typedef long long ll; 
void ExGcd(int a,int b,int &x,int &y){ 
    if(b==0){ 
        x=1; 
        y=0; 
        return ; 
    } 
    ExGcd(b,a%b,x,y); 
    int t=x; 
    x=y; 
    y=t-a/b*y; 

int main(){ 
    int t,T,rev,x; 
    int a,b; 
    scanf("%d",&T); 
    for(t=1;t<=T;t++){ 
        scanf("%d %d",&a,&b); 
        ExGcd(b,mod,rev,x); 
        printf("%d\n",((rev*a)%mod+mod)%mod); 
    } 

 

O(n)打素數表

[cpp] 
int pn = 0,prime[MAXN],factor[MAXN];//factor[i]為i的最小素約數 
void get_prime(int n){ 
    int i,j; 
    for(i=1;i<=n;i++) 
        factor[i]=i; 
    for(i=2;i<=n;i++){ 
        if(i==factor[i])prime[pn++]=i; 
        for(j=0;j<pn && prime[j]*i<=n;j++){ 
            factor[i*prime[j]]=prime[j]; 
            if(i%prime[j]==0) 
                break; 
        } 
    } 

POJ 1845 二分(1+x+x^2...+x^n)求和
[cpp]
#include<cstdio> 
#include<cstring> 
#include<cstdlib> 
#include<cmath> 
#define mod 9901 
typedef long long ll; 
const int MAXN=10000; 
int a,b,k; 
int p[MAXN],n[MAXN]; 
ll quick(ll num,ll mi){ 
    ll ans=1; 
    while(mi){ 
        if(mi%2)ans=(ans*num)%mod; 
        num=(num*num)%mod; 
        mi/=2; 
    } 
    return ans%mod; 

ll sum(ll num,ll mi){ 
    if(mi==0)return 1; 
    if(mi%2) 
        return (sum(num,mi/2)*(1+quick(num,mi/2+1)))%mod; 
    return (sum(num,mi/2-1)*(1+quick(num,mi/2+1))+quick(num,mi/2))%mod; 

void factor(int a){ 
    int i; 
    k=0; 
    for(i=2;i*i<=a;){  //sqrt(n)的復雜度分解整數 
        if(a%i==0){ 
            p[k]=i; 
            n[k]=0; 
            while(a%i==0){ 
                n[k]++; 
                a/=i; 
            } 
            k++; 
        } 
        if(i>2)i+=2; 
        else i++; 
    } 
    if(a>1){ 
        p[k]=a; 
        n[k]=1; 
        k++; 
    }     

int main(){ 
    int i; 
    scanf("%d %d",&a,&b); 
    factor(a); 
    int ans=1; 
    for(i=0;i<k;i++) 
        ans=(ans*(sum(p[i],n[i]*b))%mod)%mod; 
    printf("%d\n",ans); 

POJ 1845 逆元的方法
[cpp] 
#include<cstdio> 
#include<cstring> 
#include<cstdlib> 
#include<cmath> 
#define mod 9901 
typedef long long ll; 
const int MAXN=10000; 
int a,b,k; 
int p[MAXN],n[MAXN]; 
 
void ExGcd(int a,int b,int &x,int &y){ 
    if(b==0){ 
        x=1; 
        y=0; 
        return ; 
    } 
    ExGcd(b,a%b,x,y); 
    int t=x; 
    x=y; 
    y=t-a/b*y; 

int reverse(int num){ 
    int rev,x; 
    ExGcd(num,mod,rev,x); 
    return rev; 

ll quick(ll num,ll mi){ 
    ll ans=1; 
    while(mi){ 
        if(mi%2)ans=(ans*num)%mod; 
        num=(num*num)%mod; 
        mi/=2; 
    } 
    return ans%mod; 

ll sum(ll num,ll mi){ 
    if(num%mod==1)    //注意到這種情況不能用逆元,因為num-1與mod不互素 
        return (mi+1)%mod; 
    return (((quick(num,mi+1)-1+mod)%mod)*reverse((num-1)%mod)%mod+mod)%mod; 

void factor(int a){ 
    int i; 
    k=0; 
    for(i=2;i*i<=a;){  //sqrt(n)的復雜度分解整數 
        if(a%i==0){ 
            p[k]=i; 
            n[k]=0; 
            while(a%i==0){ 
                n[k]++; 
                a/=i; 
            } 
            k++; 
        } 
        if(i>2)i+=2; 
        else i++; 
    } 
    if(a>1){ 
        p[k]=a; 
        n[k]=1; 
        k++; 
    } 

int main(){ 
    int i; 
    scanf("%d %d",&a,&b); 
    factor(a); 
    int ans=1; 
    for(i=0;i<k;i++) 
        ans=(ans*(sum(p[i],n[i]*b))%mod+mod)%mod; 
    printf("%d\n",ans); 


SPOJ DIVSUM

[cpp] 
#include <cstdio> 
#include <cstring> 
#include <cstdlib> 
#include <cmath> 
 
const int MAXN = 1501000, N = 500010; 
 
int pn = 0, prime[MAXN], factor[MAXN]; 
void get_prime(int n){ 
    int i,j; 
    for(i=1;i<=n;i++) 
        factor[i]=i; 
    for(i=2;i<=n;i++){ 
        if(i==factor[i])prime[pn++]=i; 
        for(j=0;j<pn && prime[j]*i<=n;j++){ 
            factor[i*prime[j]]=prime[j]; 
            if(i%prime[j]==0) 
                break; 
        } 
    } 

 
int main() 

    int cases; 
    get_prime(N); 
    scanf("%d", &cases); 
    while(cases--) 
    { 
        int n, tmpn; 
        long long ans = 1; 
        scanf("%d", &n); 
        tmpn = n; 
        while (tmpn != factor[tmpn]) 
        { 
            long long fac = factor[tmpn], mtp = fac; 
            while (tmpn % fac == 0) 
            { 
                mtp *= fac; 
                tmpn /= fac; 
            } 
            ans *= (1 - mtp) / (1 - fac); 
        } 
        if (tmpn > 1) 
            ans *= (1 + tmpn); 
        ans -= n; 
        printf("%lld\n", ans); 
    } 
 
    return 0; 

SPOJ DIVSUM 另一種做法
[cpp] 
#include<cstdio> 
using namespace std; 
int sum[500100]; 
int main() 

    int T,t,i,j,n; 
    scanf("%d",&T); 
    for(i=1;i<=500000;i++){ 
        for(j=2;i*j<=500000;j++){//若j從1開始則會算上本身 
            sum[i*j]+=i; 
        } 
    } 
    for(t=1;t<=T;t++){ 
        scanf("%d",&n); 
        printf("%d\n",sum[n]); 
    } 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved