1. 程式人生 > 實用技巧 >數論基礎

數論基礎

A - Big Number

HDU - 1212

模擬十進位制的除法

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e5+500;
int main(){
        string s;int b;
        while(cin>>s>>b){
            int a=0;
            for(int i=0;i<s.size();i++){
                a=a*10+s[i]-'0';
                a
%=b; } cout<<a<<endl; } // system("pause"); return 0; }
View Code

B - Largest prime factor

HDU - 2136

模擬埃氏篩 篩素數的過程,如果遇到素數,那麼將他的倍數標記成這個素數的標記號。n logn logn

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int
N=1e6+500; const int maxn=1e6+500; typedef long long ll; int num[N]; void work(){ memset(num,0,sizeof num); num[1]=0; int tot=1; for(int i=2;i<maxn;i++){ if(!num[i]){ num[i]=tot; for(int j=2;j*i<maxn;j++){ num[j*i]=tot; } tot
++; } } } int main(){ work(); int n; while(~scanf("%d",&n)){ printf("%d\n",num[n]); } // system("pause"); return 0; }
View Code

C - A/B

HDU - 1576

費馬小定理,素數模的x逆元為 x的p-2次方

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e6+500;
const int maxn=1e6+500;
typedef long long ll;
const ll mod=9973;
ll quickPower(ll a, ll b,ll m) {   //計算a的b次方
    ll ans = 1;
    ll base = a;
    while (b) {
        if (b & 1) {
            ans *= base;
            ans %= m;
        }
        base *= base;
        base %= m;
        b >>= 1;   //注意是b>>=1 not b>>1
    }
    return ans;
}

int main(){
    int t;cin>>t;
    while(t--){
        ll n,b;
        cin>>n>>b;
        n%=mod;
        ll xb= quickPower(b,mod-2,mod)%mod;
        
        cout<<((n*xb)%mod)<<endl;
    }


        // system("pause");
        return 0;
}
View Code

E - Bi-shoe and Phi-shoe

LightOJ - 1370

對於每一個數,查詢一個尤拉函式大於等於他的數。

先一遍線性篩尤拉函式,從小到大掃一遍,對於每一個數的尤拉函式,把每一個小於當前尤拉函式,且未被標記的標記為當前值,保證結果最小。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e6+5;
const int maxn=1e6+5;
int num[N],phi[N];
int get_ephi(int n) {
    int m = int(sqrt(n + 0.5));
    int ans = n;
    for (int i = 2; i <= m; i++) {
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            while (n % i == 0) n /= i;
        }
    }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}
void phi_table(int n) {
  for (int i = 2; i <= n; i++) phi[i] = 0;
  phi[1] = 1;
  for (int i = 2; i <= n; i++)
    if (!phi[i])
      for (int j = i; j <= n; j += i) {
        if (!phi[j]) phi[j] = j;
        phi[j] = phi[j] / i * (i - 1);
      }
}
// struct node
// {
//     int key,index;
// }a[N];
// bool cmp(node a,node b){
//     if(a.key!=b.key)return a.key<b.key;
//     else return a.index<b.index;
// }
// int check(int x){
//     int l=2,r=maxn-1,ans;
//     while(l<=r){
//         int mid=(l+r)>>1;
//         if(a[mid].key>=x)ans=mid,r=mid-1;
//         else l=mid+1;
//     }
//     return a[ans].index;
// }
void work(){
    phi_table(maxn-1);
    memset(num,0,sizeof num);
    for(int i=2;i<maxn;i++){
        int xi=phi[i];
        while(!num[xi]){
            num[xi--]=i;
        }
    }
    // for(int i=2;i<maxn;i++){
    //     a[i].key=fx[i];a[i].index=i;
    // }
    // sort(a+2,a+maxn,cmp);
    //     for(int i=1;i<maxn;i++){
    //         int tt=check(i);
    //         num[i]=tt;
    //     }
}
int main(){
    int cas=0;
    work();
    int t;cin>>t;
    while(t--){
       int n;cin>>n;
       ll sum=0;
       for(int i=1;i<=n;i++){
            int a;cin>>a;
            sum+=num[a];
       }
    printf("Case %d: %lld Xukha\n",++cas,sum);
    }
        // system("pause");
        return 0;
}
View Code

F - The Embarrassed Cryptographer

POJ - 2635

預處理素數,a模擬字串除法,但取餘很耗時間,因此三位相加,然後取餘。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
// #include<algorithm>
#include<vector>
// #include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int maxn=1e6+10;
typedef long long ll;
// int prime[maxn];
bool isprime[maxn];
int cnt=0;

char s[120];
int check(int x){
    int  sum=0;
    int len=strlen(s);
    for(int i=0;i<len;i+=3){
        int tt=0;
        for(int j=i;j<i+3&&j<len;j++){
            sum*=10;
             tt=tt*10+s[j]-'0';
        }
        sum+=tt;
        sum%=x;
    }
    sum%=x;
    if(sum==0)return 1;
    return 0;
}
int prime[maxn+50];
int visit[maxn+50];
void make_prime(){
    memset(visit,0,sizeof visit);
    memset(prime, 0,sizeof prime);
    for (int i = 2;i <= maxn; i++) {
        if (!visit[i]) {
            prime[++prime[0]] = i;      //紀錄素數, 這個prime[0] 相當於 cnt,用來計數
        }
        for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
            visit[i*prime[j]] = 1;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
}
int main(){
    make_prime();
    int L;
    while(~scanf("%s %d",s,&L)){
        if(s[0]=='0'&&L==0)break;
        bool flag=1;
        for(int p=1;prime[p]<L;p++){
            if(check(prime[p])){
               printf("BAD %d\n",prime[p]);
                flag=0;
                break;
            }
        }       
        if(flag)puts("GOOD");
    }
        // system("pause");

    return 0;
}
View Code

G - Who Gets the Most Candies?

POJ - 2886

求約數直接預處理,線段樹模擬佇列刪除元素,

應該先-1再取模+1 防止模為0的情況。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
// #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int N=5e5+50;
int n,m;
struct SEG{

    int sum[N*50];
    void push_up(int rt){
        sum[rt]=sum[(rt<<1)]+sum[rt<<1 | 1];
    }

    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1 | 1
    void build(int l,int r,int rt){
        if(l==r){
            sum[rt]=1;
            return;
        }
        int mid=(l+r)>>1;
        build(lson);
        build(rson);
        push_up(rt);
    }
    int update(int pos,int l,int r,int rt){//更新a到b區間和
        if(l==r){
            sum[rt]=0;
            return l;
        }
        int mid=(r+l)>>1;
        int res;
        if(pos<=sum[rt<<1])res=update(pos,lson);
        else res=update(pos-sum[rt<<1],rson);
        push_up(rt);
        return res;
    }


}seg;
int F[N];
void init(){
    fill(F,F+N,2);
    F[1]=1;
    for(int i=2;i+i<N;i++){
        for(int j=2*i;j<N;j+=i){
            F[j]++;
        }
    }
}
char name[N][100],maxname[100];
int num[N];
int main(){
    init(); 
    int n,k;
    while(~scanf("%d %d",&n,&k)){
        seg.build(1,n,1);
        for(int i=1;i<=n;i++){
            scanf("%s %d",name[i],&num[i]);
        }
        int maxvalue=0;
        for(int i=1;i<=n;i++){
            int cur=seg.update(k,1,n,1);
            // cout<<i<<" "<<name[cur]<<endl;
            if(F[i]>maxvalue){
                maxvalue=F[i];
                strcpy(maxname,name[cur]);
            }
            if(i==n)break;
            int tot=seg.sum[1];
            int tmp=(abs(num[cur]))%tot;
           
            if(num[cur]>=0)k=(k-1+tmp-1+tot)%tot+1;
            else k=(k-tmp-1+tot)%tot+1;
            // k=k%tot+1;
             // if(num[cur]>0) k=(k-1+tmp-1)%tot+1;
             // else k=((k-1-tmp+tot))%tot+1;
        }
        printf("%s %d\n",maxname,maxvalue);
    }
    // system("pause");
    return 0;   
}
View Code