数论

数论

Lucas 定理

对于素数 \(p\)

\[\binom{n}{m}\equiv\binom{\lfloor n/p\rfloor}{\lfloor m/p\rfloor}\binom{n\bmod p}{m\bmod p}\pmod p \]

模板

CRT

\(m_1,m_2,...\) 两两互质,求解 \(x\)

\[\begin{cases} x \equiv a_1 \pmod{m_1} \\ x \equiv a_2 \pmod{m_2} \\ \vdots \\ x \equiv a_k \pmod{m_k} \end{cases} \]

定义 \(M=\prod m_i,M_i=\frac{M}{m_i},a_i\equiv M_i^{-1}\pmod {m_i}\)

\[x\equiv\sum a_iM_i\pmod M \]

模板

exLucas 定理

与平常的 Lucas 想比 \(p\) 不是素数。

一般的,对于模数是合数的问题,我们一般都是给他变成素数相乘的形式做。

那么我们就可以求出来 \(\bmod a_i^{k_i}\) 这样的形式, 然后就转化为 CRT 问题了。

模板

欧拉定理

模板

我们知道 \(a^{p-1}\equiv1\pmod p\) 这个东西可以由欧拉定理 \(a^{\varphi(p)}\equiv1\pmod p\)\(a,p\) 互质)

显然,这个东西他是一堆数然后拼成了一个环(群论)。

ex欧拉定理

模板

扩展欧拉定理是要求 \(a^b\bmod m\) 等于多少(这和欧拉定理有啥区别)

显然的 \(a^b\equiv a^{b\bmod\varphi(m)}\pmod m\)

阶的定义:当 \(\gcd(a,m)=1\)\(a^{\varphi(m)}\equiv1\pmod m\)\(a^{k}\equiv1\pmod m\)\(k_{min}\) 为阶 \(k=\operatorname{ord}_m(a)\)

显然有 \(\operatorname{ord}_m(a)\mid \varphi(m)\) 然后我们就可以通过质因数分解之类的来 \(O(\log_2a)\) 做了

原根

原根就是在阶的基础上 \(\operatorname{ord}_m(a)=\varphi(m)\)\(a\) 就是原根。

\(m=1,2,4,p^a,2p^a\) 其中 \(p\) 是奇素数。

求原根没有什么好的办法直接暴力求,问题怎么判断是不是原根,同求阶的方法就行。

性质:当 \(m\) 为质数时,\(\{g^0,g^1,...,g^{m-2}\}\)\(1\sim m-1\) 的排列

例题 \(1\):P6091

这道题教我们如何快速求原根,先判掉没有原根的数数,然后可以先求出最小的原根 \(g\),时间复杂度是 \(O(n^{0.25}\log_2n)\) (不会证明)。

有个推论:若有原根,则这个数的原根数量为 \(\varphi(\varphi(n))\)

接下来,若 \(\gcd(k,\varphi(n))=1\)\(g^k\)\(g\) 的原根,正确性很显然,用欧拉定理就可以得出,唯一性可以发现假设(为了方便) \(k\) 为第一个互质的,那么 \(g^{(1,k)}\) 绝对不成立(欧拉定理),设存在一个 \(t\) 使得他不是 \(k\) 中的一个,因为在环中,绝对有 \(g\equiv t^u\pmod n\) 然后感觉这个东西就很逆元,可以反证出来。

\(\mathscr{Code:}\)

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>

#define ll long long
// #define int ll
#define pii pair<int,int>
#define ull unsigned long long
using namespace std;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
char buf[1<<21], *p1=buf,*p2=buf;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define getchar() gc()
ll rd(){
    ll s=0; char ch=getchar(); bool fu=0;
    while(ch<'0'||ch>'9')ch=='-'?fu=1:0,ch=getchar();
    while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
    return fu?-s:s;
}

const int N=1e6+10;
int phi[N],pr[N],cnt;
bool vis[N],st[N];

void init(){
    phi[1]=1;
    for(int i=2;i<N;++i){
        if(!vis[i])pr[++cnt]=i,phi[i]=i-1;
        for(int j=1;1ll*pr[j]*i<N;++j){
            vis[i*pr[j]]=true;
            if(i%pr[j]==0){
                phi[i*pr[j]]=phi[i]*pr[j];
                break;
            }
            phi[i*pr[j]]=phi[i]*(pr[j]-1);
        }
    }
    st[2]=st[4]=1;
    for(int i=2;i<=cnt;++i){
        ll p = pr[i];
        for(ll j=p;j<N;j*=p) st[j]=1;
        for(ll j=2*p;j<N;j*=p) st[j]=1;
    }
}
int gcd(int a,int b){
    return !b?a:gcd(b,a%b);
}
ll qpow(ll a,int b,int mod){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
int tot,p[N];
void calc(int x){
    tot=0;
    for(int i=2;i*i<=x;++i){
        if(x%i==0){
            p[++tot]=i;
            while(x%i==0)x/=i;
        }
    }
    if(x>1)p[++tot]=x;
}
bool check(int x,int n){
    if(qpow(x,phi[n],n)!=1)return 0;
    for(int i=1;i<=tot;++i)
        if(qpow(x,phi[n]/p[i],n)==1)return 0;
    return 1;
}
int run(int n){
    if(n==2)return 1;
    if(n==4)return 3;
    calc(phi[n]);
    for(int i=2;i<n;++i)
        if(check(i,n))return i;
    return 0;
}
int ans[N],res;
void getans(int gen,int p){
    res=0;
    int cur=1;
    for(int i=1;i<=phi[p];++i){
        cur=cur*gen%p;
        if(gcd(i,phi[p])==1)ans[++res]=cur;
    }
}
inline void Solve(){
    int n=rd(),d=rd();
    if(!st[n]){
        puts("0\n");
        return;
    }
    int gen=run(n);
    getans(gen,n);
    sort(ans+1,ans+res+1);
    printf("%d\n",res);
    for(int i=1;i<=res/d;++i)
        printf("%d ",ans[i*d]);
    puts("");
}

signed main(){
    // freopen("input.in","r",stdin);
    // ios::sync_with_stdio(false);
    // cin.tie(0), cout.tie(0);
    init();
    int T=rd();
    while(T--)Solve();
    return 0;
}

BSGS

模板

问题自己看,那么显然有 \(0\le l\le p-1\)

那么我们可以分解成 \(l=iT+j\)\(i\in[0,T-1],j\in[0,T-1]\) 则我们可以表示出来 \(l\in[0,T^2-1]\)

那么就好做了。

\(a^{iT}\equiv ba^{-j}\)

桶装即可。

整除分块

P2261

首先可以转化成 \(\sum (k-i\lfloor\frac{k}{i}\rfloor)=nk-\sum i\lfloor\frac{k}{i}\rfloor\)

求右面的式子可以将其划分为 \(i\le T\)\(T<i\) 第一部分重复少但个数少,第二部分重复多但个数多,所以我们对于第一部分直接枚举,第二部分只有 \(\frac{k}{T}\) 种数,所以直接枚举数就行。

void Solve() {
	rd(n, k);
	ans = n * k, n = min(n, k);
	function<ll(int, int)> sum = [&](int l, int r) {
		return 1ll * (l + r) * (r - l + 1) >> 1;
	};
	for (int l = 1, r, cur; l <= n;) {
		r = min(n, k / (cur = k / l));
		ans -= sum(l, r) * cur;
		l = r + 1;
	}
	printf("%lld\n", ans);
}
posted @ 2026-08-02 11:49  static_inline  阅读(3)  评论(0)    收藏  举报