数论

一、欧几里得算法

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}

若gcd (a, b)=m,则gcd (a/m, b/m)=1

最小公倍数 LCM(a,b)=a/gcd(a,b)*b

题目:POJ2773---Happy 2006

由题目可知k的范围明显比m大,想到往周期性靠拢

由gcd性质可得gcd(a, b)=gcd(b*t+a, b),题目求的是与m互质的数即gcd(i,m)=1=gcd(m*t+i,m),具有周期性,周期为m,注意k%num==0的情况

#include<cstdio>
using namespace std;
const int n_max=1e6+5;
int f[n_max];
int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
int main()
{
    int m,k;
    while(~scanf("%d%d",&m,&k))
    {
        int num=0;
        for(int i=1; i<=m; ++i)
            if(gcd(i,m)==1)
                f[num++]=i;
        printf("%d\n",k%num==0?(k/num-1)*m+f[num-1]:k/num*m+f[k%num-1]);
    }
    return 0;
}

二、

矩阵快速幂运算

struct matr
{
    int m[n_max][n_max];
};
matr x,y;
const int mod=1e9+7;
for(int i=0; i<n; ++i)
    y.m[i][i]=1;
matr operator*(matr a,matr b)
{
    matr c;
    for(int i=0; i<n; ++i)
        for(int j=0; j<n; ++j)
        {
            c.m[i][j]=0;
            for(int k=0; k<n; ++k)
                c.m[i][j]=(c.m[i][j]+a.[i][k]*b.m[k][j])%mod;
        }
}
matr qpow(matr a,matr b,int k)
{
    while(k)
    {
        if(k&1) b=b*a;
        a=a*a;
        k>>1;
    }
    return b;
}
qpow(x,y,k);

快速积运算

int qmul(int a,int b)
{
    int ans=0;
    while(b)
    {
        if(b&1)
            ans+=a;
        a<<=1;
        b>>=1;
    }
    return ans;
}

快速幂运算

int qpow(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)
            ans*=a;
        a*=a;
        b>>=1;
    }
    return ans;
}

快速积取模

int Modmul(int a,int b,int mod)
{
    int ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%mod;
        a<<=1;
        a%=mod;
        b>>=1;
    }
    return ans;
}

快速幂取模

int Modpow(int a,int b,int mod)
{
    int ans=1;
    while(b)
    {
        if(b&1)
            ans=Modmul(ans,a,mod);
        a=Modmul(a,a,mod);
        b>>=1;
    }
    return ans;
}

素数筛

bool vis[n_max];
int prime[n_max],cnt;
void sieve()
{
    memset(vis,0,sizeof(vis));
    int m=sqrt(n_max);
    for(int i=2;i<=m;++i)
    {
        if(!vis[i])
        prime[cnt++]=i;
        for(int j=i;j<n_max;j+=i)
            vis[j]=true;
    }
}

三、质因数分解

题目1:POJ2992---Divisors

题目2:ACM-ICPC 2018 南京赛区网络预赛J---Sum

定义f(N)为N的分解组合数

①如果N本身是一个质数,它只能分解为1*N和N*1,f(N)=2

②如果N分解的两个乘数质数p和N/p=x,如果x可以整除p*p,很明显f(N)=0(N无论如何分解,其中一个乘数必定含有p的次方大于等于2);如果x不能整除p,那么对于x的每一个分解,p都可以乘以其中一个乘数而不产生重复,所以f(N)=f(x)*2;如果x仅能整除p,x分解出来的每一个组合必定有其中一个乘数含有p,但f(N)!=f(x),因为此时产生了重复(例如6*3),但可以换一种思维来想,如果再将x的p因子剔除得到y,那么对于y的每一种分解,p都必须同时与两个乘数相乘(将两个p分开),f(N)=f(y)=f(x/p)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cctype>
#include<cmath>
#include<map>
#include<vector>
#include<utility>
#define For(i,x,y) for(int i=x;i<=y;++i)
#define Fov(i,x,y) for(int i=x;i>=y;--i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
#define lowbit(x) x&-x
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
    while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=2e7+5;
ll f[n_max];
bool vis[n_max];
int prime[n_max];

int main()
{
	int cnt=0;
	f[1]=1;
	for(int i=2;i<n_max;++i)
	{
	    if(!vis[i])
        {
            prime[cnt++]=i;
            f[i]=2;
        }
        for(int j=0;j<cnt&&prime[j]*i<n_max;++j)
        {
            int x=i*prime[j];
            vis[x]=true;
            if(i%prime[j]==0)
            {
                if(i%(prime[j]*prime[j])==0)
                    f[x]=0;
                else
                    f[x]=f[i/prime[j]];
                break;
            }
            else
                f[x]=2*f[i];
        }
	}
	for(int i=2;i<n_max;++i)
        f[i]+=f[i-1];
	int T;
	scanf("%d",&T);
	while(T--)
    {
        int n;
        scanf("%d",&n);
        printf("%lld\n",f[n]);
    }
	return 0;
}

四、欧拉函数

欧拉函数φ(x):对于整数n,小于n的正整数中与n互质的数的数目

①求单个欧拉函数

int euler(int n)
{
    int ans=n;
    for(int i=2; i*i<=n; ++i)
        if(n%i==0)
        {
            ans=ans/i*(i-1);
            while(n%i==0) n/=i;
        }
    if(n>1) return ans=ans/n*(n-1);
    return ans;
}

②筛法求欧拉函数表

int euler[n_max];
for(int i=2; i<n_max; ++i)
    euler[i]=i;
for(int i=2; i<n_max; ++i)
    if(euler[i]==i)
        for(int j=i; j<n_max; j+=i)
            euler[j]=euler[j]/i*(i-1);

题目:POJ2480---Longge's problem

五、费马大定理

题目:HDU6441---Find Integer

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cctype>
#include<cmath>
#include<map>
#include<vector>
#define For(i,x,y) for(int i=x;i<=y;++i)
#define Fov(i,x,y) for(int i=x;i>=y;--i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
using namespace std;
typedef long long ll;
inline int read()
{
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
    while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
const int inf=0x3f3f3f3f;

int main()
{
    int n,a,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&a);
        if(n==0||n>2)
            printf("-1 -1\n");
        else if(n==1)
            printf("%d %d\n",1,a+1);
        else
        {
            if(a&1)
            {
                int x=(a-1)>>1,b=2*x*x+2*x;
                printf("%d %d\n",b,b+1);
            }
            else
            {
                int x=a>>1,b=x*x-1;
                printf("%d %d\n",b,b+2);
            }
        }
    }
	return 0;
}

六、费马小定理

如果p为质数,且a与p互质,则有 ,可推出

取模运算法则

①若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p)和(a * c) ≡ (b * c) (%p);

②若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a - c) ≡ (b - d) (%p),(a * c) ≡ (b * d) (%p),(a / c) ≡ (b / d) (%p);

题目1:HDU6440---Dream

对于任意比质数p小的数a,b, a、b、a+b与p肯定互质,因而根据费马小定理和取模运算法则有 ,因而可以定义a+b为(a+b)%p,a*b为(a*b)%p

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cctype>
#include<cmath>
#include<map>
#include<vector>
#define For(i,x,y) for(int i=x;i<=y;++i)
#define Fov(i,x,y) for(int i=x;i>=y;--i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
using namespace std;
typedef long long ll;
inline int read()
{
    char ch=getchar();
    int x=0, f=1;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while('0'<=ch&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int p;
        scanf("%d",&p);
        For(i,0,p-1)
        For(j,0,p-1)
        printf("%d%c",(i+j)%p,j==p-1?'\n':' ');
        For(i,0,p-1)
        For(j,0,p-1)
        printf("%d%c",(i*j)%p,j==p-1?'\n':' ');
    }
    return 0;
}

欧拉定理

若正整数 a , n 互质,则  a^φ(n)≡1(mod n) ;推论:若正整数 a , n 互质,a^p≡a^(p mod φ(n)) (mod n)

题目2:ACM-ICPC 2018 焦作赛区网络预赛G---Give Candies

尝试几个数后得出规律ans=2^(n-1);n的范围极大,题目很明显求的是超高次幂;根据欧拉定理的推论可实现降幂。

#include <bits/stdc++.h>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define L(_) (_)<<1
#define R(_) ((_)<<1)|1
#define fi first
#define se second
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
    while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=1e5+10;
const ll mod=1e9+7;
char s[n_max];
int main()
{
	//freopen("in.txt","r",stdin);
	int T; si(T);
	ll mod1=mod-1;
	while(T--)
    {
        ss(s);
        int len=strlen(s);
        ll n=0,ans=1,x=2;
        Fo(i,0,len) n=(n*10+s[i]-'0')%mod1;
        --n;
        while(n)
        {
            if(n&1) ans=ans*x%mod;
            x=x*x%mod;
            n>>=1;
        }
        printf("%lld\n",ans);
    }
	return 0;
}

七、莫比乌斯反演

整除分块:求

for(int l=1,r;l<=n;l=r+1)
{
    r=n/(n/l);
    ans+=(r-l+1)*(n/l);
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值