In mathematics you don't understand things, you just get used to them.

标签 number theory 下的文章

阶(multiplicative order)

$\textbf{Def.}$:$\delta_m(a)$ 为最小的 $n$ 使得 $a^n\equiv 1\pmod m$,其中 $(a,m)=1$。

Observation 1:$\boxed{a^0\not\equiv a^1\not\equiv\dots\not\equiv a^{\delta_m(a)-1}\pmod m}$。

$\textbf{Proof}$:若 $\exists i,j,s.t.0\leqslant i<j<\delta_m(a),a^i\equiv a^j\pmod m$,则 $a^{i-j}\equiv 1\pmod m$,又 $i-j<\delta_m(a)$,矛盾。

$\blacksquare$

Observation 2:$\boxed{\delta_m(a)\mid\varphi(m)}$。

$\textbf{Proof}$:由欧拉定理: $a^{\varphi(m)}\equiv 1\pmod m$,因为 $1^x=1$,所以如果存在 $x_0$ 使得 $a^{x_0}\equiv 1\pmod m$,那么 $x_0$ 倍数也一定可以,也就是说存在周期性,所以 $\delta_m(a)\mid\varphi(m)$。BTW,同时也有若 $a^n\equiv 1\pmod m$,则 $\delta_m(a)\mid n$。

$\blacksquare$

顺便可以知道若 $a^p\equiv a^q\pmod m$,则 $p\equiv q\pmod{\delta_m(a)}$。

Lemma 1:设 $m\in\mathbb{N}^*$,$a,b\in\mathbb{Z}$,$(a,m)=(b,m)=1$,则 $\boxed{\delta_m(ab)=\delta_m(a)\delta_m(b)}$ 的重要条件是 $(\delta_m(a),\delta_m(b))=1$。

$\textbf{Proof}$:略,具体见此处。

Lemma 2:设 $k\in\mathbb{N}$,$m\in\mathbb{N}^*$,$a\in\mathbb{Z}$,$(a,m)=1$,则 $\boxed{\delta_m(a^k)=\frac{\delta_m(a)}{(\delta_m(a),k)}}$。

$\textbf{Proof}$:略,具体见此处。

原根(primitive root)

$\textbf{Def.}$:对于 $(a,m)=1$,若 $\delta_m(a)=\varphi(m)$,则称 $a$ 是模 $m$ 的原根。

Lemma 1(判定定理):设 $m\geqslant3$,$(a,m)=1$,则 $a$ 为模 $m$ 的原根当且仅当 $\boxed{\forall p\in\mathbb{P},p\mid\varphi(m),a^{\frac{\varphi(m)}{p}}\not\equiv1\pmod m}$。

$\textbf{Proof}$:必要性显然,充分性证明见此处。

Lemma 2(数量定理):若 $m$ 存在原根,则其原根数量为 $\boxed{\varphi(\varphi(m))}$。

$\textbf{Proof}$:略,具体见此处。

Lemma 3(存在定理):$m$ 存在原根当且仅当 $\boxed{m=2,4,p^\alpha,2p^\alpha}$,其中 $p$ 为奇素数,$a\in\mathbb{N}^*$。

$\textbf{Proof}$:略,具体见此处。

若 $m$ 存在原根,则最小原根 $\leqslant m^\frac{1}{4}$。

大约是翻译了一下官方题解?

@Description@

对于一个整数序列 $P=(P_{1},\dots,P_{m})$,定义 $f(P)$ 为一个序列 $Q$ 满足:

  • $Q_{i}=P_{i}+P_{i+1}$,其中 $i\in[1,m)$;
  • $f(P)=(P_{1},Q_{1},\dots,P_{m-1},Q_{m-1},P_{m})$。

给出正整数 $a,b,N$,其中 $a,b\leqslant N$,令序列 $A=(a,b)$,令序列 $B$ 为一下操作的结果:

  • 做 $N$ 次令 $A=f(A)$.
  • 删除 $A$ 中大于 $B$ 的数。

求 $B_{l,\dots r}$。

@Solution@

◆ The Coefficient Sequence

构造最终的 $A$ 序列的过程是这样的:

$$ a,b \\ a,a+b,b \\ a,2a+b,a+b,a+2b,b \\ a,3a+b,2a+b,3a+2b,a+b,2a+3b,a+2b,a+3b,b \\ \dots $$

可以发现有对称性。此时我们先不关心 $a,b$ 以及 $N$ 的大小,反之,我们来观察其序列系数,也就是把每个元素看成 $xa+yb$,其系数的 $(x,y)$,上例的序列系数即

$$ (1,0),(0,1) \\ (1,0),(1,1),(0,1) \\ (1,0),(2,1),(1,1),(1,2),(0,1) \\ (1,0),(3,1),(2,1),(3,2),(1,1),(2,3),(1,2),(1,3),(0,1) \\ \dots $$

以下我们称其为 Coefficient Sequence

◆ The properties of the Coefficient Sequence

现在我们来观察 Coefficient Sequence 的性质。

Observation 1:在 Coefficient Sequence 中相邻的两个二元组 $(x_{S},y_{S}),(x_{T},y_{T})$,都有: $x_{S}y_{T}-x_{T}y_{S}=1$。

使用数学归纳法(induction)即证。

Observation 2:对于两个 两个二元组 $(x_{S},y_{S}),(x_{T},y_{T})$,如果他们满足 $x_{S}y_{T}-x_{T}y_{S}=1$,那么它们在 Coefficient Sequence 中相邻,即 Observation 1 是充要条件

不会证,大概意会一下吧

Observation 3:对于一个二元组 $(x,y)$,如果 $\gcd(x,y)=1$,那么 $(x,y)$ 会出现在 Coefficient Sequence 中。

比较显然,以至于官方题解没有给出证明。

Observation 4:在任意时刻,所有在 Coefficient Sequence 中的 $(x,y)$ 总是呈从左到右的关于值 $\frac{y}{x}$ 递增(令 $\frac{x}{0}=\infty$)。

◆ The sequence $B$ in other words

现在描述序列 $B$ 变得更加容易,现在我们这样描述它:

对于所有二元组 $(x,y)$ 满足 $x,y,s.t.x,y\in\mathbb{N},\gcd(x,y)=1,ax+by\leqslant N$,我们对其按 $\frac{y}{x}$ 排序后形成一个二元组序列 $\{(x_{i},y_{i})\}$,则 $B_{i}=ax_{i}+by_{i}$。

◆ Computing $B_{n}$

现在我们来考虑原问题的简化版,我们来计算 $B_{n}$。让我们把这个描述成一个计数问题(通过二分 $\frac{y}{x}$):

给定正整数 $a,b,N$,以及一个有理数 $c$(二分的值),求二元组 $(x,y)\neq(0,0)$ 的数量,其中 $(x,y)$ 满足

  • $ax+by\leqslant N$;
  • $\gcd(x,y)=1$;
  • $\frac{y}{x}\leqslant c$。

我们令 $F(N)$ 为以上问题的答案,同时令 $G(N)$ 为去掉 $\gcd(x,y)=1$ 限制的答案。$G(N)$ 的式子可以很方便的写出来: $G(N)=\sum_{y=1}^{N}\max\{\lfloor\frac{N-by}{a}\rfloor-\lfloor\frac{y}{c}\rfloor+1,0\}$,同时我们还可以写出 $G(N)=\sum_{d=1}^{N}F(\lfloor\frac{N}{d}\rfloor)$。那么再根据 Möbius inversion formula,我们可以表示出 $F(N)=\sum_{d=1}^{N}\mu(d)G(\lfloor\frac{N}{d}\rfloor)$。于是计算该问题答案的复杂度就是 $\mathcal{O}(N)$。

但是此时我们知道了 $B_{n}$ 的 $\frac{y_{n}}{x_{n}}$,怎么知道 $(x_{n},y_{n})$ 呢?我们可以再做一个二分。观察出这样一个规律:若令 $l=(1,0),r=(0,1)$,那么中间位置就是 $l+r$。于是我们可以再次做一个二分,利用 $\frac{y}{x}$ 单调来做 check。

顺带一提,这个还可以使用 类欧几里得 来计算。

◆ Computing $B_{l,\dots,r}$

可以发现这个东西可以知二求一,于是求出 $B_{l},B_{l+1}$ 就行了。当然也可以求出 $B_{l},B_{r}$ 然后做二分搜索。

Description

Link.

$$\sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p\gcd(i\cdot j,i\cdot k,j\cdot k)\times \gcd(i,j,k)\times \left(\frac{\gcd(i,j)}{\gcd(i,k)\times \gcd(j,k)}+\frac{\gcd(i,k)}{\gcd(i,j)\times \gcd(j,k)}+\frac{\gcd(j,k)}{\gcd(i,j)\times \gcd(i,k)}\right)$$

Solution

考虑把 $i,j,k$ 分别唯一分解,显然 $ij,jk,ik$ 并没有增加唯一分解后使用的质数数量,仅仅改变了指数。再考虑 $\gcd$ 的本质就是唯一分解后对指数取 $\min$ 的乘积结果。钦定研究一个质因数,设 $i,j,k$ 该质因数的指数分别为 $a,b,c$,则 $\gcd$ 上该位的指数为 $\min(a,b,c)$,我们做这样一个容斥:$\min(a+b,b+c,a+c)=\min(a,b)+\min(a,c)+\min(b,c)-\min(a,b,c)$。证明不妨设 $a<b<c$ 即证。

那么有:

$$ \sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k=1}^{p}(ij,ik,jk)(i,j,k)\left(\frac{(i,j)}{(i,k)(j,k)}+\frac{(i,k)}{(i,j)(j,k)}+\frac{(j,k)}{(i,j)(i,k)}\right) \\ \begin{aligned} &=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k=1}^{p}\frac{(i,j)(i,k)(j,k)}{(i,j,k)}(i,j,k)\frac{(i,j)^{2}+(i,k)^{2}+(j,k)^{2}}{(i,j)(i,k)(j,k)} \\ &=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k=1}^{p}(i,j)^{2}+(i,k)^{2}+(j,k)^{2} \\ \end{aligned} $$

注意到三个部分并无本质不同,我们设 $F(n,m,p)=p\sum_{i=1}^{n}\sum_{j=1}^{m}(i,j)^{2}$,答案即 $F(n,m,p)+F(n,p,m)+F(m,p,n)$。接下来推导 $F$,同时钦定 $n<m$:

$$ \sum_{i=1}^{n}\sum_{j=1}^{m}(i,j)^{2} \\ \begin{aligned} &=\sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}d^{2}[(i,j)=1] \\ &=\sum_{d=1}^{n}d^{2}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\sum_{t\mid(i,j)}\mu(t) \\ &=\sum_{T=1}^{n}\sum_{d\mid T}d^{2}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\mu(\frac{T}{d}) \\ \end{aligned} $$

令 $f(x)=\sum_{d|x}d^{2}\mu(\frac{x}{d})$,显然是个积性函数,$f(p)=p^{2}-1$,不需要 $k$ 次方就能做了欸。

#include<bits/stdc++.h>
#define con(typ) const typ
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static int s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
con(int) MOD=1e9+7;
int T,n,m,p;
ll mu[20000010],f[20000010],tag[20000010],prime[20000010],cnt;
void makePrime(int l)
{
    mu[1]=f[1]=1;
    for(ll i=2;i<=l;++i)
    {
        if(!tag[i])    prime[++cnt]=i,f[i]=(i*i%MOD-1+MOD)%MOD;
        for(int j=1;j<=cnt && prime[j]*i<=l;++j)
        {
            tag[i*prime[j]]=1;
            if(i%prime[j])    f[i*prime[j]]=f[i]*f[prime[j]]%MOD;
            else
            {
                f[i*prime[j]]=f[i]*prime[j]%MOD*prime[j]%MOD;
                break;
            }
        }
    }
    for(int i=1;i<=l;++i)    f[i]+=f[i-1],f[i]%=MOD;
}
ll cal(int n,int m,int p)
{
    if(n>m)    n^=m^=n^=m;
    ll res=0;
    for(int l=1,r;l<=n;l=r+1)
    {
        r=std::min(n/(n/l),m/(m/l));
        res+=(f[r]-f[l-1]+MOD)*(n/l)%MOD*(m/l)%MOD;
        res%=MOD;
    }
    return (res*p%MOD+MOD)%MOD;
}
int main()
{
    makePrime(2e7);
    for(sf(T);T;--T)    sf(n),sf(m),sf(p),pf(((cal(n,m,p)+cal(n,p,m)%MOD)+cal(m,p,n))%MOD);
    return 0;
}

「CF 1514A」Perfectly Imperfect Array

Link.

就看序列中是否存在不为平方数的元素即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
ll T,n,x;
bool check(ll x)
{
    for(ll i=1;i*i<=x;++i)    if(i*i==x)    return true;
    return false;
}
int main()
{
    for(sf(T);T;--T)
    {
        sf(n);
        bool fl=0;
        for(int i=1;i<=n;++i)
        {
            sf(x);
            if(!check(x))    fl=1;
        }
        if(fl)    puts("YES");
        else    puts("NO");
    }
    return 0;
}

「CF 1514B」AND 0, Sum Big

Link.

和最大的情况就是每个数都只有一个 $0$(二进制下),于是答案就是 $n^{k}$。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
const int MOD=1e9+7;
int main()
{
    int T,n,k;
    for(sf(T);T;--T)
    {
        sf(n),sf(k);
        ll ans=1;
        for(int i=1;i<=k;++i)    ans*=n,ans%=MOD;
        pf(ans);
    }
    return 0;
}

「CF 1514C」Product 1 Modulo N

Link.

把所有与 $n$ 互质的数拉出来,如果 product 不满足要求,就把最后一个剔除。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int n;
ll op(ll x,ll y){return x*y%n;}
int main()
{
    sf(n);
    std::vector<ll> ans;
    for(int i=1;i<=n;++i)    if(__gcd(i,n)==1)    ans.emplace_back(i);
    if(accumulate(ans.begin(),ans.end(),1,op)!=1)    ans.pop_back();
    pf(ans.size());
    for(int i:ans)    pf(i,' ');
    return 0;
}

「CF 1514D」Cut and Stick

Link.

答案是 $\max\{1,2x-l\}$,$l$ 为区间长度,$x$ 为众数出现次数。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const int MAXN = 5e5 + 5, MAXM = 720 + 5;

char buf[1 << 21], *p1 = buf, *p2 = buf;
#define getchar( ) ( p1 == p2 && ( p2 = ( p1 = buf ) + fread( buf, 1, 1 << 21, stdin ), p1 == p2 ) ? EOF : *p1 ++ )

template<typename _T>
void read( _T &x ){
    x = 0; char c = getchar( ); _T f = 1;
    while( c < '0' || c > '9' ){ if( c == '-' )    f = -1; c = getchar( ); }
    while( c >= '0' && c <= '9' ){ x = ( x << 3 ) + ( x << 1 ) + ( c & 15 ); c = getchar( ); }
    x *= f;
}

template<typename _T>
void write( _T x ){
    if( x < 0 ){ putchar( '-' ); x = -x; }
    if( x > 9 ){ write( x / 10 ); }
    putchar( x % 10 + '0' );
}

template<typename _T>
void swapp( _T &one, _T &another ){ int temp = one; one = another; another = temp; }

template<typename _T>
_T MIN( _T one, _T another ){ return one > another ? another : one; }

template<typename _T>
_T MAX( _T one, _T another ){ return one > another ? one : another; }

int N, M;
int cube, each, kase, isa[MAXN], cnt[MAXN], pos[MAXN], vis[MAXN], bel[MAXN];
int lps[MAXM], rps[MAXM], App[MAXM][MAXM];
vector<int> disc, fur[MAXN];

int getID( int x ){ return lower_bound( disc.begin( ), disc.end( ), x ) - disc.begin( ) + 1; }

void build( ){
    memset( cnt, 0, sizeof( cnt ) );
    for( int i = 1; i <= cube; ++ i ){
        kase ++;
        for( int j = i; j <= cube; ++ j ){
            App[i][j] = App[i][j - 1];
            for( int k = lps[j]; k <= rps[j]; ++ k ){
                if( vis[isa[k]] != kase )    cnt[isa[k]] = 0;
                cnt[isa[k]] ++; App[i][j] = MAX( App[i][j], cnt[isa[k]] );
                vis[isa[k]] = kase;
            }
        }
    }
    memset( cnt, 0, sizeof( cnt ) );
}

int query( int opl, int opr ){
    if( bel[opl] == bel[opr] ){
        int res = 0; kase ++;
        for( int i = opl; i <= opr; ++ i ){
            if( vis[isa[i]] != kase )    cnt[isa[i]] = 0;
            cnt[isa[i]] ++; res = MAX( res, cnt[isa[i]] );
            vis[isa[i]] = kase;
        }
        return res;
    }
    int res = 0;
    res = App[bel[opl] + 1][bel[opr] - 1];
    for( int i = opl; i <= rps[bel[opl]]; ++ i ){
        int lim = fur[isa[i]].size( ) - 1;
        while( pos[i] + res <= lim && fur[isa[i]][pos[i] + res] <= opr )    res ++;
    }
    for( int i = lps[bel[opr]]; i <= opr; ++ i ){
        while( pos[i] - res >= 0 && fur[isa[i]][pos[i] - res] >= opl )    res ++;
    }
    return res;
}

signed main( ){
    read( N ); read( M ); each = 720; cube = ( N - 1 ) / each + 1;
    for( int i = 1; i <= N; ++ i ){ read( isa[i] ); disc.push_back( isa[i] ); }
    sort( disc.begin( ), disc.end( ) );
    disc.erase( unique( disc.begin( ), disc.end( ) ), disc.end( ) );
    for( int i = 1; i <= N; ++ i ){
        isa[i] = getID( isa[i] );
        fur[isa[i]].push_back( i );
        pos[i] = fur[isa[i]].size( ) - 1;
    }
    for( int i = 1; i <= cube; ++ i ){
        lps[i] = rps[i - 1] + 1; rps[i] = rps[i - 1] + each;
        if( i == cube )    rps[i] = N;
        for( int j = lps[i]; j <= rps[i]; ++ j )    bel[j] = i;
    }
    build( );
    int opl, opr;
    while( M -- > 0 ){
        read( opl ); read( opr );
        write( max( 1, 2 * query( opl, opr ) - ( opr - opl + 1 ) ) );
        putchar( '\n' );
    }
    return 0;
}

「CF 1514E」Baby Ehab's Hyper Apartment

Link.

// Oops, something went wrong.

Description

Link.

$ n $ distinct integers $ x_1,x_2,\ldots,x_n $ are written on the board. Nezzar can perform the following operation multiple times.

  • Select two integers $ x,y $ (not necessarily distinct) on the board, and write down $ 2x-y $ . Note that you don't remove selected numbers.

Now, Nezzar wonders if it is possible to have his favorite number $ k $ on the board after applying above operation multiple times.

Solution

Let us onsider how to express all the number we can express.
Since $2x-y=x+(x-y)$, the expression is $x_{i}+\sum_{j,k}x_{j}-x{k}$.
Since $x_{i}=x_{1}+(x_{1}-(x_{1}+(x_{1}-x_{i})))$, the expression could be written as $x_{1}+\sum_{i}x_{i}-x_{1}$, which means the answer exists where $\sum_{i}x_{i}-x_{1}=K-x_{1}$ has solutions.
Beout's identity works.

#include<bits/stdc++.h>
typedef long long ll;
#define sf(x) scanf("%d",&x)
#define ssf(x) scanf("%lld",&x)
int main()
{
    int T,n;
    ll k;
    sf(T);
    while(T-->0)
    {
        sf(n),ssf(k);
        ll g=0,x1,x;
        ssf(x1);
        for(int i=2;i<=n;++i)    ssf(x),g=std::__gcd(x-x1,g);
        puts((k-x1)%g==0?"YES":"NO");
    }
    return 0;
}