HIT暑期集训 数论进阶

中国剩余定理,求解符合若干个x%a[i]≡b[i]的式子的答案x,其中a两两互质(模板中求出的最小的非负整数解)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[3],b[3]={23,28,33};
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 tmp=x;
    x=y; 
    y=tmp-a/b*y;
}
int crt(int n)
{
    int i,tmp,ans=0,lcm=1,x,y;
    for (i=0;i<n;++i) lcm*=b[i];
    for (i=0;i<n;++i)
    {
        tmp=lcm/b[i];
        exgcd(tmp,b[i],x,y);
        x=(x%b[i]+b[i])%b[i];
        ans=(ans+tmp*x*a[i])%lcm;
    }
    return (ans+lcm)%lcm;
}
int main()
{
    int p,e,i,d;
    int cnt=0,ans;
    while (scanf("%d%d%d%d",&p,&e,&i,&d)!=EOF)
    {
        if (p==-1) break;
        a[0]=p;
        a[1]=e;
        a[2]=i;
        ans=crt(3);
        if (ans<=d) ans+=21252;
        cnt++;
        printf("Case %d: the next triple peak occurs in %d days.\n",cnt,ans-d);
    } 
    return 0;
}
中国剩余定理,模板题 POJ 1006

 扩展中国剩余定理,求解符合若干个x%m[i]≡r[i]的式子的答案x,其中m不一定两两互质(不会证明,我就记个模板。。)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 15
using namespace std;
typedef long long ll;
ll a[maxn],r[maxn];
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if (b==0)
    { 
        x=1;y=0; 
        return a;
    }
    ll gcd=exgcd(b,a%b,x,y);
    ll tmp=x;
    x=y; 
    y=tmp-a/b*y;
    return gcd;
}
ll ex_crt(int n,ll lim)
{
    ll M=a[1],R=r[1],x,y,d;
    for (int i=2;i<=n;i++)
    {
        d=exgcd(M,a[i],x,y);
        if ((R-r[i])%d) return 0;
        x=(R-r[i])/d*x%a[i];
        R-=M*x;
        M=M/d*a[i];
        R%=M;
    }
    ll ans=(R%M+M)%M;
    if (ans==0) return (lim-ans)/M;
    if (ans>lim) return 0;
    return (lim-ans)/M+1;
}
int main()
{
    int n,lim,i,T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&lim,&n);
        for (i=1;i<=n;i++) scanf("%lld",&a[i]);
        for (i=1;i<=n;i++) scanf("%lld",&r[i]);
        printf("%lld\n",ex_crt(n,lim));
    } 
    return 0;
}
扩展中国剩余定理,模板题HDU 1573

Miller-Rabin参考博客

B    UVA 11327

先求出1e6内的欧拉函数,求出它的前缀和,二分查找分母x,然后从0至x枚举直到找到答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000005
using namespace std;
typedef long long ll;
ll phi[maxn],sum[maxn],ans1,ans2;
const int lim=1000000;
int gcd(int x,int y)
{
    if (y==0) return x;
    return gcd(y,x%y);
}
void prework()
{
    int i,j;
    phi[1]=2;
    for (i=2;i<=lim;i++)
    {
        if (!phi[i]) 
        {
            for (j=i;j<=lim;j+=i)
            {
                if (!phi[j]) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
             
            }
        }
    }
    for (i=1;i<=lim;i++) sum[i]=sum[i-1]+phi[i];
}
void work(ll x)
{
    int i,l=0,r=lim,mid;
     while (l<=r)
    {
        mid=(l+r)>>1;
        if (sum[mid]<x) l=mid+1;
        else r=mid-1;
    } 
    /*l=lower_bound(sum+1,sum+lim+1,x)-sum;
    //另一种替代二分的方法 */
    x-=sum[l-1];
    for (i=0;i<=l;i++)
    {
        if (gcd(i,l)==1) x--;
        if (x==0)
        {
            ans1=i;ans2=l;
            return;
        }
    }
}
int main()
{
    ll n;
    int i,T;
    prework();
    while (scanf("%lld",&n)!=EOF && n!=0)
    {
        work(n);
        printf("%d/%d\n",ans1,ans2);
    } 
    return 0;
}
View Code

D    POJ 3904

E    HDU 2588

F    HDU 4704

题意:(我没看懂题目)求N的划分数。

答案显然为2N-1,由于N很大(10100000),这里要使用费马小定理,即当p是一个素数且与a互质时,ap-1%p≡1,

于是令N=N%(mod-1),快速幂求2N-1即可(注意考虑求出来的N为0的情况)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 1000000007
#define maxn 100005
using namespace std;
typedef long long ll;
char s[maxn];
int pow(int x,int k)
{
    int now=x,re=1;
    while (k)
    {
        if (k&1) re=(1ll*re*now)%mod;
        k>>=1;
        now=(1ll*now*now)%mod;
    }
    return re;
}
int main()
{
    int i,len,x;
    while (scanf("%s",s)!=EOF)
    {
        x=0;
        len=strlen(s);
        for (i=0;i<len;i++)
        {
            x=(1ll*x*10+s[i]-'0')%(mod-1);//费马小定理
        }
        x=(x-1+mod-1)%(mod-1);
        printf("%d\n",pow(2,x));
    }
    return 0;
}
View Code

G    SPOJ LCMSUM

H    POJ 1811

先用Miller_Rabin算法进行素数判断,再用Pollard_rho分解因子。(模板题)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<time.h>
#include<map> 
using namespace std;
typedef long long ll;
const int rep=50;
map<ll,int>mp;
ll qmul(ll a,ll b,ll mod)
{
    ll ans=0;
    a=a%mod;
    while (b)
    {
        if (b&1) ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
ll qpow(ll a,ll b,ll mod)
{
    ll ans=1;
    a=a%mod;
    while (b)
    {
        if (b&1) ans=qmul(ans,a,mod);
        a=qmul(a,a,mod);
        b>>=1;
    }
    return ans;
}
int MR(ll n,int repeat)
{
    if (n==2 || n==3) return 1;
    int i,j,s=0;
    ll d=n-1;
    while (!(d&1))
    {
        s++;
        d>>=1;
    }
    for (i=0;i<repeat;i++)
    {
        ll a=rand()%(n-3)+2;
        ll x=qpow(a,d,n);
        ll y=0;
        for (j=0;j<s;j++)
        {
            y=qmul(x,x,n);
            if (y==1 && x!=1 && x!=n-1) return 0;
            x=y;
        }
        if (y!=1) return 0;
    }
    return 1;    
}
 
ll gcd(ll a,ll b)
{
    if (b==0) return a;
    else return gcd(b,a%b);
}
ll Pollard_Rho(ll n, int c)
{
    ll i=1,k=2,x=rand()%(n-1)+1,y=x;
    while (1)
    {
        i++;
        x=(qmul(x,x,n)+c)%n;
        ll p=gcd((y-x+n)%n,n);
        if (p!=1 && p!=n) return p;
        if (y==x) return n;
        if (i==k)
        {
            y=x;
            k<<=1;
        }    
    }
}
void Find(ll n, ll c)
{
    if (n==1) return;
    if (MR(n,rep))
    {
        mp[n]++;
        return;
    }
    ll p=n;
    while (p>=n) p=Pollard_Rho(p,c--);
    Find(p,c);
    Find(n/p,c);
}
int main()
{
    ll n;
    int i,T;
    srand(time(NULL));
    scanf("%d",&T);
    while (T--)
    {
        scanf("%lld",&n);
        mp.clear();
        if (MR(n,rep)) printf("Prime\n");
        else 
        {
            Find(n,rand()%(n-1)+1);
            map<ll,int>::iterator it=mp.begin();
            printf("%lld\n",it->first);
        }
    }
    return 0;
}
View Code

I    CodeForces 1106F

posted @ 2020-08-26 17:50  lsy_kk  阅读(133)  评论(0编辑  收藏  举报