數論中的一些基礎算法

1.篩素數

const int maxn=100005;
int prime[maxn];
bool vis[maxn*10];
int cnt;
void getPrime()
{
    int N=1000000;
    int m=sqrt(N+0.5);
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=m;i++) {
        if(vis[i]==0) {
            for(int j=i*i;j<=N;j+=i)
                vis[j]=1;
        }
    }
    cnt=0;
    for(int i=2;i<=N;i++) {
        if(!vis[i])
            prime[cnt++]=i;
    }
}
2.判斷一個數a是不是素數,int範圍內,可以篩出sqrt(a)以內的素數。

bool isPrime(int a)
{
    if(a<2) return false;
    for(int i=0;i<cnt;i++) {
        if(prime[i]*prime[i]>a)
            break;
        if(a%prime[i]==0)
            return false;
    }
    return true;
}
3。long long範圍內判素數,米勒羅賓

bool test (ll n,ll a,ll d)
{
  if(n==2)
    return true;
  if(n==a)
    return true;
  if((n&1)==0)
    return false;
  while(!(d&1))
    d=d>>1;
  LL t=pow_mod(a,d,n);
  while((d!=n-1)&&(t!=1)&&(t!=n-1))
  {
    t=(ll)t*t%n;
    d=d<<1;
  }
  return (t==n-1||(d&1)==1);
}
bool isPrime(ll n)
{
  if(n<2)
    return false;
  ll a[]= {2,3,5,7,61};
  for(int i=0; i<=4; i++)
    if(!test(n,a[i],n-1))
      return false;
  return true;
}

4.大組合數取模,n,m較小時預處理階乘和逆元就可以了,n,m在long long範圍,p<=1e5,p是素數,用lucas定理。

hdu3037 求C(n+m,m)%p

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<bitset>
#define fi first
#define se second
#define pii pair<int,int>
#define ll long long
#define inf 1<<30
#define eps 1e-8
using namespace std;
const int maxn=100005;
ll n,m,p;
ll jiech[maxn];
ll powMod(ll a,ll b,ll p)
{
    if(b==0) return 1;
    ll ans=powMod(a,b/2,p);
    ans=ans*ans%p;
    if(b&1)
        ans=ans*a%p;
    return ans;
}
ll lucas(ll n,ll m,ll p)
{
    ll ret=1;
    while(n&&m){
        ll a=n%p,b=m%p;
        if(a<b) return 0;
        ret=(ret*jiech[a]*powMod(jiech[b]*jiech[a-b]%p,p-2,p))%p;
        n/=p;
        m/=p;
    }
    return ret;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%I64d%I64d%I64d",&n,&m,&p);
        jiech[0]=1;
        for(int i=1;i<=p;i++)
            jiech[i]=jiech[i-1]*i%p;
        printf("%I64d\n",lucas(n+m,m,p));
    }
    return 0;
}

5.n,m在long long 範圍,求C(n,m)%(p1*p2*p3*...*pk),pi是質數,pi<=1e5

用lucas求出所有C(n,m)%pi,中國剩餘定理求解。

hdu 5446

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<bitset>
#define fi first
#define se second
#define pii pair<int,int>
#define ll long long
#define inf 1<<30
#define eps 1e-8
using namespace std;
const int maxn=100005;
ll jiech[maxn];
ll inv[maxn];
ll p[10];
ll r[10];
ll n,m,k;
ll mod;
ll powMod(ll a,ll b,ll p)
{
    if(b==0) return 1;
    ll ans=powMod(a,b/2,p);
    ans=ans*ans%p;
    if(b&1)
        ans=ans*a%p;
    return ans;
}
ll lucas(ll n,ll m,ll p)
{
    ll ret=1;
    while(n&&m){
        ll a=n%p,b=m%p;
        if(a<b) return 0;
        ret=(ret*jiech[a]*inv[b]%p*inv[a-b]%p)%p;
        n/=p;
        m/=p;
    }
    return ret;
}
void gcd(ll a, ll b, ll &d, ll &x, ll &y)
{
    if (b == 0) {
        d = a, x = 1, y = 0;
    } else {
        gcd(b, a%b, d, y, x);
        y -= x * (a / b);
    }
}
ll china(ll n, ll m[], ll a[])
{
    ll aa = a[0];
    ll mm = m[0];
    for(int i=0;i<n;i++) {
        ll sub = (a[i] - aa);
        ll d, x, y;
        gcd(mm, m[i], d, x, y);
        if (sub % d) return -1;
        ll new_m = m[i] / d;
        new_m = (sub / d * x % new_m + new_m) % new_m;
        aa = mm * new_m + aa;
        mm = mm * m[i] / d;
    }
    aa = (aa + mm) % mm;
    return aa;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%I64d%I64d%d",&n,&m,&k);
        for(int i=0;i<k;i++) {
            scanf("%I64d",&p[i]);
            mod=p[i];
            jiech[0]=1;
            for(int j=1;j<mod;j++)
                jiech[j]=jiech[j-1]*j%mod;
            inv[mod-1]=powMod(jiech[mod-1],mod-2,mod);
            for(int j=mod-2;j>=0;j--)
                inv[j]=inv[j+1]*(j+1)%mod;
            r[i]=lucas(n,m,mod);
        }
        printf("%I64d\n",china(k,p,r));
    }
    return 0;
}






發佈了169 篇原創文章 · 獲贊 18 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章