数学数论学习笔记

平方和公式

  $\sum n^2=\frac{n*(n+1)*(2n+1)}{6}$

立方和公式

  $\sum n^3=(\frac{n*(n+1)}{2})^2$

一些推导

  $\sum_{i}^{n}\sum_{j}^{n}ij=\sum_{i}^{n}i^3$

  证明:对于一个$i$,它对答案的贡献为$i\cdot [(\sum_{j}^{i-1}j)+(\sum_{j}^{i}j)]$

     因为前$i-1$个数分别会乘一次$i$,$i$又会将$1$到$i$全乘一遍,贡献就是它们的和

     $i\cdot [(\sum_{j}^{i-1}j)+(\sum_{j}^{i}j)]=i\cdot (\frac{i(i-1)}{2}+\frac{i(i+1)}{2})=i^3$

线性筛素数

for (int i = 2; i <= N; i++)
{
    if (!st[i]) prime.pb(i);
    for (int j = 0; j < prime.size(), prime[j] * i <= N; j++)
    {
        st[prime[j] * i] = true;
        if (i % prime[j] == 0) break;
    }
}

反素数与因子个数

  n的质因数分解为$n=p_{1}^{k_{1}}+p_{2}^{k_{2}}+...+p_{m}^{k_{m}}$

  则n的因子个数为$(k_{1}+1)*(k_{2}+1)*...*(k_{m}+1)$

  线性筛因子个数

d[1] = 1;//d为因子个数
for (int i = 2; i <= n; ++i) 
{
    if (!v[i]) v[i] = 1, p[++tot] = i, d[i] = 2, num[i] = 1;
    for (int j = 1; j <= tot && i <= n / p[j]; ++j)
    {
        v[p[j] * i] = 1;
        if (i % p[j] == 0)
        {
            num[i * p[j]] = num[i] + 1;
            d[i * p[j]] = d[i] / num[i * p[j]] * (num[i * p[j]] + 1);
            break;
        }
        else 
        {
            num[i * p[j]] = 1;
            d[i * p[j]] = d[i] * 2;
        }
    }
}

  求因子数为n的最小数

prime[]= { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 };

dfs(0, 1, 1, 64);
//ans为最后的答案
void dfs(ULL depth, ULL temp, ULL num, ULL up)//当前递归到的质因数 这些质因数结合得到的值 因子个数 上一个质因数的次方
{
    if (num > n || depth >= 16) return;
    if (num == n && ans > temp)
    {
        ans = temp;
        return;
    }
    for (int i = 1; i <= up; i++)
    {
        if (temp / prime[depth] > ans) break;
        dfs(depth + 1, temp = temp * prime[depth], num * (i + 1), i);
    }
}

  求n以内因子最多的最小数

prime[]= { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 };

dfs(0, 1, 1, 64);
//ans为最后的答案 ans_num为最后的答案的因子数
void dfs(int depth, ULL temp, ULL num, int up) 
{
    if (depth >= 16 || temp > n) return;
    if (num > ans_num) 
    {
        ans = temp;
        ans_num = num;
    }
    if (num == ans_num && ans > temp) ans = temp;
    for (int i = 1; i <= up; i++)
    {
        if (temp * prime[depth] > n) break;
        dfs(depth + 1, temp *= prime[depth], num * (i + 1), i);
    }
    return;
}

欧几里得算法

  最小公约数$gcd$:

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

  最小公倍数$lcm$

int lcm(int a, int b) { return a * b / gcd(a, b); }

扩展欧几里得定理

  求$ax+by=gcd(a,b)$的一组可行解

int exgcd(int a, int b, int& x, int& y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

解线性同余方程

  求解$ax\equiv c(\textit{mod b})$

  $ax+by=c$等价于$ax\equiv c(\textit{mod b})$

  通过扩展欧几里得可以求出一组可行解

  若$gcd(a,b)=1$,且$x_0,y_0$为一组可行解,则该方程的任意解可以表示为$x=x_0+bt,y=y_0-at$且对于任意整数$t$都成立

  求最小整数解,$x=(x\textit{ mod t}+t)\textit{mod t},t=\frac{b}{gcd(a,b)}$

欧拉函数

  $\varphi (n)$为小于等于$n$的与$n$互质的数的个数

  $\sum_{d|n} \varphi (d)=n$

  他是积性函数,即若有$gcd(a,b)=1$,则$\varphi (a)*\varphi (b)=\varphi (a*b)$

  当$n$为奇数时,$\varphi (2n)=\varphi (n)$

  求解欧拉函数$\varphi (n)=n\prod_{i=1}^{s}(1-\frac{1}{p_{i}})$

  其中$p_{i}$为n的质因数

  线性筛欧拉函数

for (int i = 2; i <= n; i++) phi[i] = 0;
phi[1] = 1;
for (int i = 2; i <= n; i++)
{
    if (!phi[i])
    {
        for (int j = i; j <= n; j += i)
        {
            if (!phi[j]) phi[j] = j;
            phi[j] = phi[j] / i * (i - 1);
        }
    }
}

 

欧拉定理

  若$gcd(a,m)=1$,则$a^{\varphi (m)}\equiv 1(modm)$

  扩展欧拉定理

  $a^{b}\equiv \left\{\begin{matrix} a^{\textrm{b mod }\varphi (p)}\textit{ },gcd(a,p)=1 & \\ a^{b},gcd(a,p)\neq 1,b<\varphi (p) & \\ a^{\textit{b mod }\varphi (p)+\varphi (p)},gcd(a,p)\neq p,b>\varphi (p) & \end{matrix}\right.(\textit{mod p})$

费马小定理

  若$gcd(a,p)=1$,则$a^{p-1}\equiv 1(\textit{mod p})$

  求逆元可$a^{p-2}\equiv a^{-1}(\textit{mod p})$

裴蜀定理

  $a,b$是不全为0的整数,则存在整数$x,y$使得$ax+by=c,gcd(a,b)|c$

线性求逆元

inv[1] = 1;
for (int i = 2; i <= n; ++i)
{
  inv[i] = (p - p / i) * inv[p % i] % p;
}

  线性求任意n个数的逆元

s[0] = 1;
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p;
sv[n] = qpow(s[n], p - 2);
for (int i = n; i >= 1; --i) sv[i - 1] = sv[i] * a[i] % p;
for (int i = 1; i <= n; ++i) inv[i] = sv[i] * s[i - 1] % p;

线性同余方程

  求一组可行解,可以把$ax\equiv c(\textit{mod b})$看作$ax+by=c$,之后用扩展欧几里得,若不满足$gcd(a,b)|c$则无解

  求所有解,任意解可表示为$x=x^{0}+bt$,$y=y^{0}+at$,其中$t\in \mathbb{Z}$

  求最小解,$x=(\textit{x mod t+t})\textit{mod t}$,其中$t=\frac{b}{gcd(a,b)}$

中国剩余定理(CRT)

  $m_{i}$两两互质,求$\left\{\begin{matrix}x\equiv a_{1}(\textit{mod }m_{1}) & \\ x\equiv a_{2}(\textit{mod }m_{2}) & \\ x\equiv a_{3}(\textit{mod }m_{3}) & \\ ... & \\ x\equiv a_{k}(\textit{mod }m_{k}) & \end{matrix}\right.$  

  伪代码:

    $M=\prod m_{i}$

    $\textit{for i=1 to k}$

      $mi=\frac{M}{m_{i}}$

      $b=inv(mi,m_{i})$

      $ans=(ans+a[i]*mi*b)mod M$

   扩展中国剩余定理

  $m_{i}$两两不互质

int exCRT()
{
    int x, y, k;
    int M = b[1], ans = a[1];
    for (int i = 2; i <= n; i++)
    {
        int a = M, b = b[i], c = (a[i] - ans % b + b) % b;
        int gcd = exgcd(a, b, x, y), bg = b / gcd;
        if (c % gcd != 0) return -1; 

        x = mul(x, c / gcd, bg);
        ans += x * M;
        M *= bg;
        ans = (ans % M + M) % M;
    }
    return (ans % M + M) % M;
}

Lucas定理

  当$p$为质数,$C\binom{n}{m}\equiv C\binom{n/p}{m/p}*C\binom{\textit{n mod p}}{\textit{m mod p}}\textit{mod p}$

  扩展Lucas

   待填

BSGS

  基础

  求$a^{x}\equiv b(\textit{mod p})$ 

  令$x=A\left \lceil \sqrt{p} \right \rceil-B$,其中$0\leq A,B\leq \left \lceil \sqrt{p} \right \rceil$,则有$a^{A\left \lceil \sqrt{p} \right \rceil-B}\equiv b(\textit{mod p})$,转换成$a^{A\left \lceil \sqrt{p} \right \rceil}\equiv ba^{B}(\textit{mod p})$,之后算出$ba^{B}$的所有取值存下来,之后再枚举$A$,看是否有符合的$ba^{B}$,从而得到所有的$x$

int m = ceil(sqrt(p));
for (int i = 1; i <= m; i++)
{
    hash1[qpow(a, i, p) * b % p] = i;
}
int q = qpow(a, m, p), ans = 1;
for (int i = 1; i <= m; i++)
{
    ans = 1ll * ans * q % p;
    if (hash1[ans])
   {
        ans = i * m - hash1[ans];
        printf("%lld", (ans % p + p) % p);
        return 0;
    }
}

  扩展BSGS

  BSGS - OI Wiki (oi-wiki.org)

 

拉格朗日插值

  由$n$个点$(x_{i},y_{i})$可以确定一个多项式$y=f(x)$,求$f(k)$的值,对$mod$取模

for (int i = 1; i <= n; i++)
{
    s1 = y[i] % mod;
    s2 = 1ll;
    for (int j = 1; j <= n; j++)
    {
        if (i != j)
        {
            s1 = s1 * (k - x[j]) % mod, s2 = s2 * ((x[i] - x[j] % mod) % mod) % mod;
        }
    }   
    ans += s1 * inv(s2) % mod;
    ans = (ans + mod) % mod;
}

 数论分块

  用于求含有$\left \lfloor \frac{n}{i}\right \rfloor$的求和式($n$为常数)

  找到一个最大的$j$,使得$\left \lfloor \frac{n}{i} \right \rfloor=\left \lfloor \frac{n}{j} \right \rfloor$

  此时$j=\left \lfloor \frac{n}{\left \lfloor \frac{n}{i} \right \rfloor} \right \rfloor$

  例如[Luogu 2261],求$ans=\sum_{i=1}^{n}(\textit{k mod i})=\sum_{i=1}^{n}k-i\left \lfloor \frac{k}{i} \right \rfloor$

int ans = n * k;
for (int l = 1, r; l <= n; l = r + 1) //区间[l,r]内的k/i都相同
{  
  if (k / l != 0)
    r = min(k / (k / l), n);
  else
    r = n; 
  ans -= (k / l) * (r - l + 1) * (l + r) / 2;  
}

  若求$\sum_{i=1}^{min(n,m)}\left \lfloor \frac{n}{i} \right \rfloor\left \lfloor \frac{m}{i} \right \rfloor$则把$r=n/(n/i)$换成$r=min(n/(n/i),m/(m/i))$

关于积性函数、狄利克雷卷积、莫比乌斯反演 铃悬的数学小讲堂——狄利克雷卷积与莫比乌斯反演 - 铃悬 的博客 - 洛谷博客 (luogu.com.cn)

为什么我觉得下面这三个知识点是数论最简单的东西

积性函数

  定义

  若函数$f(x)$满足$f(1)=1$且$\forall x,y\in \mathbb{N_{+}},gcd(x,y)=1$都有$f(x)*f(y)=f(xy)$,则称$f(x)$为积性函数

  若函数$f(x)$满足$f(1)=1$且$\forall x,y\in \mathbb{N_{+}}$都有$f(x)*f(y)=f(xy)$,则称$f(x)$为完全积性函数

  性质

  若$f(x),g(x)$均为积性函数,则下列函数也为积性函数:

          $h(x)=f(x^{p})$

          $h(x)=f^{p}(x)$

          $h(x)=f(x)g(x)$

          $h(x)=h(x)=\sum_{d|x}f(d)g(\frac{x}{d})$

  设$x=\prod p_{i}^{k_{i}}$,

  若$F(x)$为积性函数,则$F(x)=\prod F(p_{i}^{k_{i}})$

  若$F(x)$为完全积性函数,则$F(x)=\prod F(p_{i})^{k_{i}}$

 Dirichlet卷积

  两个数论函数$f,g$的Dirichlet卷积为

              $(f*g)(n)=\sum_{d|n}f(d)g(\frac{n}{d})$

  Dirichlet卷积满足以下性质

  交换律$(f*g=g*f)$

  结合律$(f*g)*h=f*(g*h)$

  分配率$f*(g+h)=f*g+f*h$

  $f*\varepsilon =f$,其中$\varepsilon$为Dirichlet卷积的单位元,定义为$\varepsilon(n)=[n=1]$

 莫比乌斯函数

  莫比乌斯函数$\mu $定义为

      $\mu(n)=1,n=1$

      $\mu(n)=0,n$含有次数超过$1$的因子

      $\mu(n)=(-1)^{k},k$为$n$的次数为$1$的质因子个数

  它是积性函数,且

      $\sum_{d|n}\mu(d)=\left\{\begin{matrix}1,n=1 & \\ 0,n\neq 1 & \end{matrix}\right.$

  反演结论:$\begin{bmatrix}gcd(i,j)=1\end{bmatrix}\Leftrightarrow \sum_{d|gcd(i,j)}\mu(d)$

  线性筛莫比乌斯函数

mu[1] = 1;
for (int i = 2; i <= n; ++i)
{
  if (!flg[i]) p[++tot] = i, mu[i] = -1;
  for (int j = 1; j <= tot && i * p[j] <= n; ++j) 
  {
    flg[i * p[j]] = 1;
    if (i % p[j] == 0)
    {
      mu[i * p[j]] = 0;
      break;
    }
    mu[i * p[j]] = -mu[i];
  }
}

莫比乌斯反演

  两个数论函数$f(n),g(n)$

  若$f(n)=\sum_{d|n}g(d)$,则$g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d})$

  若$f(n)=\sum_{n|d}g(d)$,则$g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)$

  例题:[HAOI 2011] Problem b ,[BAOJ 2154]Crash的数字表格,[SDOI2015]约数个数和,[Luogu 3768]简单的数学题 

二次剩余

  若存在$x$使得$x^{2}\equiv a(\textit{mod p})$,且$a$不是$p$的倍数,则称$a$为模$p$的二次剩余

  求解二次剩余便是给出$a$求出$x$

  解的数量:

  对于$x^{2}\equiv n(\textit{mod p})$,能满足$n$是模$p$的二次剩余的$n$一共有$\frac{p-1}{2}$个

  证明:

    $(p-x)^{2}\equiv x^{2}(\textit{mod p})$,所以我们只看$x\in [1,\frac{p-1}{2}]$的情况

    若存在$x,y$使得$x^{2}\equiv y^{2}(\textit{mod p})$

    则有$x^{2}-y^{2}\equiv 0(\textit{mod p})$

      $(x-y)(x+y)\equiv 0(\textit{mod p})$

    因为$-p<x+y<p,-p<x-y<p,x+y\neq 0,x-y\neq $,所以不存在$x,y$使得$x^{2}\equiv y^{2}(\textit{mod p})$

  勒让德符号:

    $\left ( \frac{n}{p} \right )$

    若其的值为$1$则$n$为二次剩余,若为$-1$则$n$不是二次剩余,若为$0$则$p|n$

  欧拉判别:

    $\left ( \frac{n}{p} \right )=n^{\frac{p-1}{2}}(\textit{mod p})$

  证明:

  OI_Wiki

求解二次剩余:

  Cipolla算法:

  OI_Wiki

  定义$i^{2}=a^{2}-n$,则解为$(a+i)^{\frac{p+1}{2}}$

 1 int t;
 2 ll n, p;
 3 ll w;
 4 
 5 struct num {  //建立一个复数域
 6   ll x, y;
 7 };
 8 
 9 num mul(num a, num b, ll p) {  //复数乘法
10   num ans = {0, 0};
11   ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p;
12   ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p;
13   return ans;
14 }
15 
16 ll binpow_real(ll a, ll b, ll p) {  //实部快速幂
17   ll ans = 1;
18   while (b) {
19     if (b & 1) ans = ans * a % p;
20     a = a * a % p;
21     b >>= 1;
22   }
23   return ans % p;
24 }
25 
26 ll binpow_imag(num a, ll b, ll p) {  //虚部快速幂
27   num ans = {1, 0};
28   while (b) {
29     if (b & 1) ans = mul(ans, a, p);
30     a = mul(a, a, p);
31     b >>= 1;
32   }
33   return ans.x % p;
34 }
35 
36 ll cipolla(ll n, ll p) {
37   n %= p;
38   if (p == 2) return n;
39   if (binpow_real(n, (p - 1) / 2, p) == p - 1) return -1;
40   ll a;
41   while (1) {  //生成随机数再检验找到满足非二次剩余的a
42     a = rand() % p;
43     w = ((a * a % p - n) % p + p) % p;
44     if (binpow_real(w, (p - 1) / 2, p) == p - 1) break;
45   }
46   num x = {a, 1};
47   return binpow_imag(x, (p + 1) / 2, p);
48 }
View Code

快速莫比乌斯变换FMT

  一般用来解决类似于 $C_x=\sum_{i \cup j =x}A_iB_j$  的问题,其中 $x,i,j$ 表示为集合

  详解见 传送门

  模板: ( $n$ 表示全集大小)

void FMT(int *A)
{
    for (int i = 1; i < (1 << n); i <<= 1)
        for (int p = i << 1, j = 0; j < (1 << n); j += p)
            for (int k = 0; k < i; ++k)
                A[i + j + k] += A[j + k];
}

void reFMT(int *A)
{
    for (int i = 1; i < (1 << n); i <<= 1)
        for (int p = i << 1, j = 0; j < (1 << n); j += p)
            for (int k = 0; k < i; ++k)
                A[i + j + k] -= A[j + k];
}

int main()
{
    FMT(a), FMT(b);
    for (int i = 0; i < 1 << n; i++)
        a[i] *= b[i];
    reFMT(a); // a即为要求的C
}
View Code

 

  扩展: (不一定正确)

  $A_i$ 表示 $a$ 中状态为 $i$ 的方案数, $B_i$ 表示 $b$ 中状态为 $i$ 的方案数

  求 $C_x=\sum_{i \& j=x}A_iB_j$ 

inline void FMT(int *a)
{
    for (int j = 0; j < n; j++)
        for (int i = 0; i < 1 << n; i++)
            if (i >> j & 1)
                a[i & ~(1 << j)] += a[i];
}

inline void reFMT(int *a)
{
    for (int j = 0; j < n; j++)
        for (int i = 0; i < 1 << n; i++)
            if (i >> j & 1)
                a[i & ~(1 << j)] -= a[i];
}

int main()
{
    FMT(A), FMT(B);
    for (int i = 0; i < 1 << n; i++)
        A[i] *= B[i];
    reFMT(A);
}
View Code

 

快速沃尔什变换FWT

  一般用来解决类似于$C_{i}=\sum_{j\bigoplus k}^{}A_{j}B_{k}$的问题,其中$\bigoplus$表示而二元位运算的一种

  详解见OI_Wiki

  与、或、异或运算皆是将$A$、$B$转换后,$C$便等于$A*B$,之后再给C来一遍逆转换即可

  或:

  当$flag =1$时为转换,$flag=-1$时为逆转换

for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
    {
        for (int i = 0; i < n; i += o)
        {
            for (int j = 0; j < k; j++)
            {
                f[i + j + k] = add(f[i + j + k], mul(f[i + j], flag));
            }
        }
    }
View Code

  与:

  同上

for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
    {
        for (int i = 0; i < n; i += o)
        {
            for (int j = 0; j < k; j++)
            {
                f[i + j] = add(f[i + j], mul(f[i + j + k], flag));
            }
        }
    }
View Code

  异或:

  当$flag=1$时为转换,当$flag=\frac{1}{2}$时为逆转换

for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
    {
        for (int i = 0; i < n; i += o)
        {
            for (int j = 0; j < k; j++)
            {
                f[i + j] = add(f[i + j], f[i + j + k]);
                f[i + j + k] = sub(sub(f[i + j], f[i + j + k]), f[i + j + k]);
                f[i + j] = mul(f[i + j], flag), f[i + j + k] = mul(f[i + j + k], flag);
            }
        }
    }
View Code

  实现:

  其中$mul$是$a[i]*=b[i]$,与运算和异或运算类似

putin(a),putin(b);//输入
OR(a,1),OR(b,1);//转换
mul(a,b);//相乘
OR(a,-1);//逆转换
putout(a);//此时a=c,输出

 阶

  若$(a,m)=1$,使$a^l\equiv 1(\textit{mod m})$成立的最小的$l$称为$a$模$m$的阶,记为$ord_ma$

  若$ord_ma=l$,则$ord_ma^t=\frac{l}{(t,l)}$

  有欧拉定理,设$ord_ma=l$,则$a^n\equiv 1(\textit{mod m})$当且仅当$l|n$,特别的,$l|\varphi (m)$

  设$p$是素数,$ord_pa=l$,那么当且仅当有$\varphi (l)$个关于模$p$的阶为$l$且两两互不同余的数

  设$ord_ma=l$,则$1,a,a^2,···,a^{l-1}$关于模$m$两两互不同余

  设$p$是素数,$l|\varphi (p)$,则存在$\varphi (p)$个关于模$p$的阶为$l$且两两互不同余的数

  若$m=p_{1}^{a_1}p_{2}^{a_2}···p_{k}^{a_k}$,则$ord_ma=[ord_{p_1}^{a_1},ord_{p_2}^{a_2},···,ord_{p_k}^{a_k}]$

 原根

  $(g,m)=1$,若$ord_mg=\varphi (m)$,则$g$为$m$的一个原根

  $g$为$m$的一个原根当且仅当${g,g^2,···,g^\varphi (m)}$构成模$m$的一个既约剩余系

  判断是否有原根

  若$m$有原根,则$m$一定为$2,4,p^a,2p^a$,其中$p$为奇素数,$a$为正整数

  求一个原根

  $(g,m)=1$,设$p_1,p_2,···,p_k$是$\varphi (m)$的所有不同的素因数,则$g$是$m$的原根,当且仅当任意$1\leq i\leq k$,都有$g^{\frac{\varphi(m)} {p_i}}\not\equiv 1(\textit{mod m})$

  板子:[Luogu6091]

快速傅里叶变换(FFT)

  超简单的快速傅里叶变换!

#define PI acos(-1)

struct Complex
{
    double x, y;
    Complex(double x = 0, double y = 0) : x(x), y(y) { }
}a[N];

Complex operator * (Complex J, Complex Q)
{
    return Complex(J.x * Q.x - J.y * Q.y, J.x * Q.y + J.y * Q.x);
}
Complex operator - (Complex J, Complex Q)
{
    return Complex(J.x - Q.x, J.y - Q.y);
}
Complex operator + (Complex J, Complex Q) 
{
    return Complex(J.x + Q.x, J.y + Q.y);
}

void FFT(Complex* A, int type)
{
    for (int i = 0; i < limit; ++i)
    {
        if (i < R[i])
            swap(A[i], A[R[i]]);
    }

    for (int mid = 1; mid < limit; mid <<= 1)
    {
        Complex wn(cos(PI / mid), type * sin(PI / mid));

        for (int len = mid << 1, pos = 0; pos < limit; pos += len)
        {
            Complex w(1, 0);

            for (int k = 0; k < mid; ++k, w = w * wn) 
            {
                Complex x = A[pos + k];
                Complex y = w * A[pos + mid + k];
                A[pos + k] = x + y;
                A[pos + mid + k] = x - y;
            }
        }
    }
    if (type == 1) return;
    for (int i = 0; i <= limit; ++i) a[i].x /= limit, a[i].y /= limit;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i <= n; ++i) scanf("%lf", &a[i].x);
    for (int i = 0; i <= m; ++i) scanf("%lf", &a[i].y);

    limit = 1;
    while (limit <= n + m) limit <<= 1, L++;
    for (int i = 0; i < limit; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    FFT(a, 1);

    for (int i = 0; i <= limit; ++i) a[i] = a[i] * a[i];
    FFT(a, -1);

    for (int i = 0; i <= n + m; ++i) printf("%d ", (int)(a[i].y / 2 + 0.5));
}
View Code

快速数论变换(NTT)

  用来快速计算卷积

  卷积:类似于 $(f*g)(x)=\sum f(i)g(n-i)$ 的形式

void NTT(int *x, int lim, int opt)
{
    register int i, j, k, m, gn, g, tmp;
    for (i = 0; i < lim; ++i)
        if (r[i] < i)
            swap(x[i], x[r[i]]);
    for (m = 2; m <= lim; m <<= 1)
    {
        k = m >> 1;
        gn = qpow(3, (P - 1) / m);
        for (i = 0; i < lim; i += m)
        {
            g = 1;
            for (j = 0; j < k; ++j, g = 1ll * g * gn % P)
            {
                tmp = 1ll * x[i + j + k] * g % P;
                x[i + j + k] = (x[i + j] - tmp + P) % P;
                x[i + j] = (x[i + j] + tmp) % P;
            }
        }
    }
    if (opt == -1)
    {
        reverse(x + 1, x + lim);
        register int inv = qpow(lim, P - 2);
        for (i = 0; i < lim; ++i)
            x[i] = 1ll * x[i] * inv % P;
    }
}

void solve()
{
    while (lim < (n << 1))
        lim <<= 1;
    for (int i = 0; i < lim; ++i)
        r[i] = (i & 1) * (lim >> 1) + (r[i >> 1] >> 1);
    NTT(A, lim, 1), NTT(B, lim, 1);
    for (int i = 0; i < lim; i++)
        C[i] = A[i] * B[i] % P;
    NTT(C, lim, -1);
}
View Code

线性基

  线性基有以下性质

  对于一个数列 $A$ 来说,若$P$为它的线性基

  $A$任意数字都能通过$P$中的一些数字异或出来
  $P$只能异或出$A$中的数或$A$中的数能异或出来的东西
  $P$中任意数都不能被$P$中其他数异或出来
  $P$中数最高位不重复

  构造线性基

inline void insert(LL x)
{
    for (int i = 62; ~i; i--)
    {
        if ((x >> i) & 1)
        {
            if (!a[i]) { a[i] = x; break; }
            else x ^= a[i];
        }
    }
}

  求数列的最大异或和

for (int i = 62; ~i; i--) ans = max(ans, ans ^ a[i]);

   求异或的不同结果中第$k$小的数

inline void find_init()//初始化
{
    cnt = 0;
    for (int i = 0; i <= 62; ++i)
    {
        for (int j = i - 1; j >= 0; --j)
            if (a[i] & (1ll << j))   a[i] ^= a[j];
        if (a[i])    tmp[cnt++] = a[i];
    }
}

inline LL find_num(LL k)//查询
{
    LL res = 0;
    k -= flag;
    if (!k) return 0;
    if (k >= (1ll << cnt)) return -1;
    for (int i = 0; i < cnt; i++)
    {
        if ((k >> i) & 1) res ^= tmp[i];
    }
    return res;
}

 生成函数

  若一个序列为$a=\begin{Bmatrix} a_1,a_2,a_3,a_4,...,a_n \end{Bmatrix}$

  则它的生成函数为$F(x)=a_1+a_2x+a_3x^2+a_4x^3+...+a_nx^{n+1}$

  

  若$a=\begin{Bmatrix} 1,1,1,1,1,... \end{Bmatrix}$

  则它的生成函数为$F(x)=1+x+x^2+x^3+x^4+...=\frac{1}{1-x}$

  因为$F(x)x+1=F(x)$

  解得$F(x)=\frac{1}{1-x}$

 

  其他

  $F(x)=1+ax+2ax^2+3ax^3+4ax^4+...=\frac{1}{(1-x)^a}=\sum_{n}^{\infty }C_{n+a-1}^{a-1}x^n,a$为一个常数,则第$n$项的系数为$C_{n+a-1}^{a-1}$

  $F(x)=1+x^a+x^{2a}+x^{3a}+...=\frac{1}{1-x^a}$,$a$为一个常数

 

  常见的生成函数

  $<1,1,1,1,1,\dots>,F(x) = \sum_{n\geq 1}x^n=\frac{x}{1-x}$

  $<1,0,1,0,1,\dots>,F(x) = \sum_{n\geq 0}x^{2n}=\frac{1}{1-x^2}$

  $<1,2,3,4,\dots>,F(x) = \sum_{n\geq 0}(n+1)x^n=\frac{1}{(1-x)^2}$

  $a_n=\binom{m}{n},F(x)=\sum_{n\geq0}\binom{m}{n}x^n=(1+x)^m$

  $a_n=\binom{m+n}{n},F(x)=\sum_{n\geq0}\binom{m+n}{n}x^n=\frac{1}{(1-x)^{m+1}}$

 

  生成函数一般用来求方案数

  例如:

  有$n$种砝码,每种砝码个数无限,质量分别为$1~n$克,用序列$a_i$表示第$i$个砝码能组成$m$克的方案数为$a_{i,m+1}$

  例:

  $1$克的砝码的序列为$a=\begin{Bmatrix} 1,1,1,1,1,1,1,... \end{Bmatrix}$,每种质量它都能有一种方案组成

  $3$克的砝码的序列为$a=\begin{Bmatrix} 1,0,0,1,0,0,1,0,0,1,... \end{Bmatrix}$,$3$克的砝码组成$0$克的方案数为$1$,则$a_{3,1}=1$,组成$1,2$的方案数为$0$,则$a_{3,2}=0,a_{3,3}=0$,组成$3$克的方案数为$1$,则$a_{3,4}=1$

  接下来求生成函数

  $1$克的生成函数便是$F_1(x)=1+x+x^2+x^3+...=\frac{1}{1-x}$

  $3$克的生成函数为$F_3(x)=1+x^3+x^6...=\frac{1}{1-x^3}$

  之后$\prod_{i=1}^{n}F_i(x)$便是$n$个砝码全部都用的生成函数,之后求出$x^m$的系数,该系数就是答案

 置换

  置换群 - OI Wiki

  Burnside 引理

  每个置换的不动点个数的平均数就是方案数

斯特林数  

  第一类斯特林数

  $\begin{bmatrix}n\\ k\end{bmatrix}$或$s(n,k)$,表示将$n$个两两不同的数分为$k$个互不区分的非空轮换的方案数

  一个轮换指首尾相连的环形序列,$[A,B,C,D]$视为一个轮换,则$[A,B,C,D]=[B,C,D,A]=[C,D,A,B]=[D,A,B,C]$,$[A,B,C,D]\neq [D,C,B,A]$

  $\begin{Bmatrix}n\\ k\end{Bmatrix}=\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}+(n-1)\begin{Bmatrix}n-1\\ k\end{Bmatrix}$

  同一行或同一列第一类斯特林数计算

  第二类斯特林数

  $\begin{Bmatrix}n\\ k\end{Bmatrix}$或$S(n,k)$,表示将两两不同的$n$个数分为$k$个不同的非空子集的方案数

  $\begin{Bmatrix}n\\ k\end{Bmatrix}=\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}+k\begin{Bmatrix}n-1\\ k\end{Bmatrix}$

  通项公式$\begin{Bmatrix}n\\ m\end{Bmatrix}=\sum_{i=0}^{m}\frac{(-1)^{m-i}i^n}{i!(m-i)!}$

  用途

  上升幂与普通幂转换

  上升幂:$x^{\bar n}=\prod_{k=0}^{n-1}(n+k)$

  $x^n=\sum_{k}\begin{Bmatrix}n\\ k\end{Bmatrix}(-1)^{n-k}x^{\bar{k}}$   

  $x^{\bar{n}}=\sum_{k}\begin{bmatrix}n\\ k\end{bmatrix}x^k$

  下降幂与普通幂转换

  下降幂:$x^{\underline n}=\frac{x!}{(x-n)!}=\prod_{k=0}^{n-1}(n-k)$

  下降幂一特性:$\binom{n}{k} \cdot k^{\underline{i}}=\binom{n-i}{k-i} \cdot n^{\underline{i}}$

   $x^{n}=\sum_{k}\begin{Bmatrix}n\\ k\end{Bmatrix}x^{\underline k}$   

   $x^{\underline n}=\sum_{k}\begin{bmatrix}n\\ k\end{bmatrix}(-1)^{n-k}x^k$

 求$x_n=ax_{n-1}+b$的通项公式

  $x_n=ax_{n-1}+b$

  设$x_n+c=a(x_{n-1}+c)$

  $x_n=ax_{n-1}+c(a-1)$

  $c(a-1)=b$

  $c=\frac{b}{a-1}$

  $x_n+\frac{b}{a-1}=a(x_{n-1}+\frac{b}{a-1})$

  $x_n+\frac{b}{a-1}=a^2(x_{n-2}+\frac{b}{a-1})$

  $...$

  $x_n+\frac{b}{a-1}=a^{n-1}(x_1+\frac{b}{a-1})$

行列式

  定义:$n$阶行列式是由$n^2$个数$a_{ij}$通过下式确定的一个数

  $\begin{vmatrix} a_{11}& a_{12} & ... & a_{1n} & \\  a_{21}& a_{22} & ... & a_{2n} & \\  \vdots & \vdots  &\ddots   & \vdots  & \\  a_{n1}& a_{n2} & ... & a_{nn} & \end{vmatrix}=\sum_{j_1j_2...j_n}(-1)^{\gamma (j_1...j_n)}a_{1j_1}a_{2j_1}...a_{nj_1}$

  $j_1j_2...j_n$是$1-n$的一个排列,$\gamma (j_1...j_n)$是排列中逆序对的个数

  基本定理:

  $1$ 行列互换,值不变

  $2$ 用一个数乘行列式的某行等于用这个数乘此行列式

  $3$ 如果行列式中某一行是两组数之和,则这个行列式等于两个行列式之和,这两个行列式分别以这两组数为该行,而其余各行与原行列式对应各行相同

  $4$ 交换行列式中两行,行列式反号(乘$-1$)

  $5$ 如果行列式中有两行成比例,则行列式为0

  $6$ 把一行的某个倍数加到另一行,行列式的值不变

  求行列式的值:

  高斯消元,每次将两行交换的时候改变行列式的符号,消到最后行列式的值就为$\prod a_{i,i}$乘上符号

for (int i = 0; i < n; ++i)
{
    int k = i;
    for (int j = i + 1; j < n; ++j)
        if (abs(a[j][i]) > abs(a[k][i])) k = j;
    if (abs(a[k][i]) < EPS)
    {
        det = 0;
        break;
    }
    swap(a[i], a[k]);
    if (i != k) det = -det;
    det *= a[i][i];
    for (int j = i + 1; j < n; ++j) a[i][j] /= a[i][i];
    for (int j = 0; j < n; ++j)
        if (j != i && abs(a[j][i]) > EPS)
            for (int k = i + 1; k < n; ++k) a[j][k] -= a[i][k] * a[j][i];
}
View Code

  不带实数运算的求行列式的值

int det = 1;
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            while (a[i][i])
            {
                int d = a[j][i] / a[i][i];
                for (int k = i; k < n; k++)
                {
                    a[j][k] = (a[j][k] - 1ll * d * a[i][k] % mod + mod) % mod;
                }
                swap(a[i], a[j]);
                det = -det;
            }
            swap(a[i], a[j]);
            det = -det;
        }
    }
    for (int i = 0; i < n; i++) 
        det = 1ll * det * a[i][i] % mod;
    return det;
View Code

 二项式定理

  $(a+b)^n=\sum_{i=0}^n\binom{n}{i}a^{n-i}b^i$

二项式反演

  $f_n=\sum_{i=0}^n(-1)^iC_n^ig_i \Leftrightarrow g_n=\sum_{i=0}^n(-1)^iC_n^if_i$

  $f_n=\sum_{i=0}^nC_n^ig_i \Leftrightarrow g_n=\sum_{i=0}^n(-1)^{n-i}C_n^if_i$

   $\forall m \geq n,f_n=\sum_{i=n}^mC_i^ng_i \Leftrightarrow g_n=\sum_{i=n}^m(-1)^{i-n}C_i^nf_i$

posted on 2020-12-24 22:36  ArrogHie  阅读(260)  评论(0编辑  收藏  举报