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

标签 maths 下的文章

感谢教练布置任务让我有动力写东西!。21)

其实有些非显性异类混了进去,但是你看得出来。

「codeforces - 340E」Iahub and Permutations

link。

把 $1,\dots,n$ 中剩下没被固定的数的数量记作 $s$,再把这其中不担心有会填到自己身上去的情况的数字的数量记作 $h$,则总方案为 $s!$,考虑容斥把重叠方案去除,设容斥系数为 $f$。

则可以写出答案式:$\displaystyle \sum_{i=0}^{s-h}f_i\binom{s-h}{i}(s-i)!$。然后你考虑这个过程就是“所有数随便摆的方案数减去至少一个数冲突加上至少两个数冲突...”,所以 $f_i=(-1)^i$。

#include<bits/stdc++.h>
constexpr int kMod=1e9+7;
int n,a[2100],fac[2100],ifac[2100],vis[2100],bin[2100][2100];
signed main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr),std::cout.tie(nullptr);
  fac[0]=1;
  for(int i=1; i<=2000; ++i) fac[i]=1ll*fac[i-1]*i%kMod;
  std::cin>>n;
  std::vector<int> vec;
  for(int i=1; i<=n; ++i) {
    std::cin>>a[i];
    if(~a[i]) vis[a[i]]=1;
  }
  bin[0][0]=1;
  for(int i=1; i<=n; ++i) {
    bin[i][0]=1;
    for(int j=1; j<=i; ++j) bin[i][j]=(bin[i-1][j]+bin[i-1][j-1])%kMod;
  }
  int s=0,h=0;
  for(int i=1; i<=n; ++i) {
    if(a[i]==-1) s++;
    if(vis[i]==0 && a[i]!=-1) h++;
  }
  int res=0;
  for(int i=0; i<=s-h; ++i) (res+=1ll*((i&1)?-1:1)*bin[s-h][i]*fac[s-i]%kMod)%=kMod;
  std::cout<<(res+kMod)%kMod<<"\n";
  return 0;
}

「codeforces - 520E」Pluses everywhere

link。

考虑每一个数位的贡献,这个取决于它右边第一个加号的位置,这个定了,它的系数就定了,即 $10^{s}$,其中 $s$ 为这个数位到右边第一个加号的距离减一,然后再乘一个二项式系数,当然如果这个加号在数字的最后要特殊处理。这个题是不是就做完了?

写下式子:$\displaystyle\sum_{i=0}^{n-1}\left(\left(d_i\sum_{x=0}^{n-2-i}\cdot\binom{n-x-2}{k-1}\cdot10^{x}\right)+d_i\cdot\binom{i}{k}\cdot10^{n-i-1}\right)$,然后交换求和顺序 $\displaystyle\left(\sum_{x=0}^{n-2}10^x\cdot\binom{n-x-2}{k-1}\cdot\sum_{i=0}^{n-x-2}d_i\right)+\left(\sum_{i=0}^{n-1}d_i\cdot\binom{i}{k}\cdot10^{n-i-1} \right)$。

前缀和后 $O(n)$ 算就好了。

#include<bits/stdc++.h>
constexpr int kMod=1e9+7;
int n,k,dig[100100],fac[100100],ifac[100100],pw[100100],prs[100100];
int Binpw(int x,int y) {
  int res=1;
  for(; y; y>>=1,x=1ll*x*x%kMod)
    if(y&1) res=1ll*res*x%kMod;
  return res;
}
int Bin(const int x,const int y) {
  if(x<y) return 0;
  return 1ll*fac[x]*ifac[x-y]%kMod*ifac[y]%kMod;
}
signed main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr),std::cout.tie(nullptr);
  fac[0]=pw[0]=1;
  for(int i=1; i<=100000; ++i) fac[i]=1ll*fac[i-1]*i%kMod;
  for(int i=1; i<=100000; ++i) pw[i]=1ll*pw[i-1]*10%kMod;
  ifac[100000]=Binpw(fac[100000],kMod-2);
  for(int i=99999; ~i; --i) ifac[i]=1ll*ifac[i+1]*(i+1)%kMod;
  std::cin>>n>>k;
  char *grid=new char[n];
  std::cin>>grid;
  for(int i=0; i<n; ++i) dig[i]=grid[i]-'0';
  prs[0]=dig[0];
  for(int i=1; i<n; ++i) prs[i]=(prs[i-1]+dig[i])%kMod;
  int res=0;
  for(int i=0; i<=n-2; ++i) (res+=1ll*pw[i]*Bin(n-i-2,k-1)%kMod*prs[n-i-2]%kMod)%=kMod;
  for(int i=0; i<n; ++i) (res+=1ll*dig[i]*pw[n-i-1]%kMod*Bin(i,k)%kMod)%=kMod;
  std::cout<<res<<"\n";
  return 0;
}

「codeforces - 451E」Devu and Flowers

link。

你写出这个东西的 ogf:$\displaystyle G(x)=\prod_{i=1}^n\sum_{j=0}^{f_i}x^j=\frac{\prod_{i=1}^n1-x^{f_i+1}}{(1-x)^n}=\left(\prod_{i=1}^n1-x^{f_i+1}\right)\sum_{i=0}^{\infty}\binom{n+i-1}{n-1}x^i$。

然后发现不会了,于是考虑容斥!!.。》?

然后你发现你会了!!!。。1.!0

#include<bits/stdc++.h>
constexpr int kMod=1e9+7;
int n;
long long f[30],s;
int Binpw(int x,int y) {
  int res=1;
  for(; y; y>>=1,x=1ll*x*x%kMod)
    if(y&1) res=1ll*res*x%kMod;
  return res;
}
int Bin(long long n,const long long k) {
  if(n<k) return 0;
  if(n==k) return 1;
  n%=kMod;
  int resx=1,resy=1;
  for(int i=0; i<k; ++i) {
    resx=1ll*resx*(n-i)%kMod;
    resy=1ll*resy*(i+1)%kMod; 
  }
  return static_cast<int>(1ll*resx*Binpw(resy,kMod-2)%kMod);
}
signed main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr),std::cout.tie(nullptr);
  std::cin>>n>>s;
  for(int i=0; i<n; ++i) std::cin>>f[i];
  const int kEntire=(1<<n);
  int res=0;
  for(int mask=0; mask<kEntire; ++mask) {
    long long tp=s;
    for(int j=0; j<n; ++j) {
      if(mask&(1<<j)) tp-=(f[j]+1);
    }
    (res+=((__builtin_popcount(mask)&1)?-1ll:1ll)*Bin(tp+n-1,n-1)%kMod)%=kMod;
  }
  std::cout<<(res+kMod)%kMod<<"\n";
  return 0;
}

对多步容斥不熟练啊,我建议我自己看看这个

link。

首先将问题弱化为 1-d,我们待定容斥系数 $f_i$,可以写出答案的式子:$\sum\limits_{i=a}^nf_i\binom{n}{i}2^{n-i}$。解释就是,我们想让 $\binom{n}{i}2^{n-i}$ 达到“至少”的效果,但是明显会算重,所以通过这个容斥系数 $f_i$ 达到“恰好”的效果,于是原题“至少”的答案就是这个。

每一个“恰好” $i$ 个的方案数在最终的答案中的贡献次数为 $1$,也就是说 $\sum\limits_{j=a}^if_j\binom{i}{j}=1$。这个的意思就是如果至少有 $i$ 的方案数重了,那么它一定是从前面开始重的(就是说 $1,\dots,i-1$ 的随便摆的部分跟它重了),所以从前面开始容斥。

然后就好算了,可以直接得出 $f_i=\sum\limits_{j=a}^{i-1}f_j\binom{i-1}{j-1}$,或者你也可以用下吸收公式推式子。

但实际上这个题还有一些常数的优化,具体可以看看 Siyuan 的博客。

#include<bits/stdc++.h>
#define il __inline__ __attribute__((always_inline))
constexpr int kMod=998244353;
__int128 sum;
int n,m,A,B,i,j,k;
int coef[2][3100],pw[9000100],bin[3100][3100];
il void MCase() {
  for(k=0; k<2; ++k) {
    coef[k][0]=1;
    for(int i=(k?B:A); i<=(k?m:n); ++i) coef[k][i]=1ll*(((i-(k?B:A))&1)?-1:1)*bin[i-1][(k?B:A)-1]%kMod*bin[k?m:n][i]%kMod;
  }
  int res=0;
  for(i=A; i<=n; ++i)
    for(j=B; j<=m; ++j) (res+=1ll*coef[0][i]*coef[1][j]%kMod*pw[(n-i)*(m-j)]%kMod)%=kMod;
  std::printf("%d\n",res<0?res+kMod:res);
}
signed main(int argc,char const* argv[]) {
  pw[0]=1;
  for(i=1; i<9000100; ++i) pw[i]=1ll*pw[i-1]*2%kMod;
  bin[0][0]=1;
  for(i=1; i<3100; ++i) {
    bin[i][0]=1;
    for(j=1; j<=i; ++j) bin[i][j]=(bin[i-1][j]+bin[i-1][j-1])%kMod;
  }
  for(; ~std::scanf("%d%d%d%d",&n,&m,&A,&B);) MCase();
  return 0;
}

link。

钦定 $i>j$,研究得 $(x^i-1,x^j-1)\rightleftharpoons(x^i-x^j,x^j-1)\rightleftharpoons(x^j(x^{i-j}-1),x^j-1)$,注意到 $(x^j,x^j-1)=1$ 且当 $(a,c)=1$ 时 $(ab,c)=(a,b)(a,c)$,则原式 $\rightleftharpoons(x^{i-j}-1,x^j-1)\rightleftharpoons(x^{i\bmod j}-1,x^j-1)\rightleftharpoons x^{(i,j)}-1$。

于是题目即求 $\left(\sum\limits_{i=1}^n\sum\limits_{j=1}^nx^{(i,j)}\right)-n^2$。注意到 $1\leqslant(i,j)\leqslant n$,容易想到研究每一个 $(i,j)$ 的贡献次数,设其为 $f(x)$,显然有 $f(x)=\sum\limits_{i=1}^n\sum\limits_{j=1}^n[(i,j)=x]$,观察得 $f(x)=2\times\left(\sum\limits_{i=1}^{\lfloor\frac{n}{x}\rfloor}\varphi(i)\right)-1$,则答案为 $\sum\limits_{i=1}^nx^i\cdot f(i)$,整除分块 & 等比数列求和优化即可。

#include <bits/stdc++.h>
const int MOD = 1000000007;
template <typename T>
T add(T a, T b) {
  return (a + b) % MOD;
}
template <typename T, typename... Args>
T add(T a, T b, Args... args) {
  return add(add(a, b), args...);
}
template <typename T>
T sub(T a, T b) {
  return (a + MOD - b) % MOD;
}
template <typename T>
T mul(T a, T b) {
  return a * static_cast<long long>(b) % MOD;
}
template <typename T, typename... Args>
T mul(T a, T b, Args... args) {
  return mul(mul(a, b), args...);
}
template <typename T>
void Add(T &a, T b) {
  a = add(a, b);
}
template <typename T, typename... Args>
void Add(T &a, T b, Args... args) {
  Add(a, add(b, args...));
}
template <typename T>
void Sub(T &a, T b) {
  a = sub(a, b);
}
template <typename T>
void Mul(T &a, T b) {
  a = mul(a, b);
}
template <typename T, typename... Args>
void Mul(T &a, T b, Args... args) {
  Mul(a, mul(b, args...));
}
int tag[1000100], tot, p[1000100], n, x, ph[1000100], f[1000100];
void shai(int N) {
  tag[1] = ph[1] = 1;
  for (int i = 2; i <= N; ++i) {
    if (!tag[i]) {
      p[++tot] = i;
      ph[i] = i - 1;
    }
    for (int j = 1; j <= tot && i * p[j] <= N; ++j) {
      tag[i * p[j]] = 1;
      if (i % p[j] == 0) {
        ph[i * p[j]] = ph[i] * p[j];
        break;
      }
      ph[i * p[j]] = ph[i] * ph[p[j]];
    }
  }
  for (int i = 1; i <= N; ++i) Add(ph[i], ph[i - 1]);
  for (int i = 1; i <= N; ++i) f[i] = sub(mul(ph[i], 2), 1);
}
int fp(int x, int y) {
  int res = 1;
  for (; y; y >>= 1, Mul(x, x))
    if (y & 1) Mul(res, x);
  return res;
}
int Inv(int x) { return fp(x, MOD - 2); }
int Sum(int n) { return mul(x, sub(1, fp(x, n)), Inv(sub(1, x))); }
int Sum(int l, int r) { return sub(Sum(r), Sum(l - 1)); }
signed main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr), std::cout.tie(nullptr);
  int T;
  shai(1e6);
  for (std::cin >> T; T; --T) {
    std::cin >> x >> n;
    if (x == 1) {
      std::cout << "0\n";
      continue;
    }
    int res = 0;
    for (int l = 1, r; l <= n; l = r + 1) {
      r = n / (n / l);
      Add(res, mul(Sum(l, r), f[n / l]));
    }
    std::cout << sub(res, mul(n, n)) << '\n';
  }
  return 0;
}

原来的标题是:『「水」CRT 的构造本质』。

对于一个单元线性同余方程组 $x\equiv a_i\pmod{r_i}$,考虑构造一个 $\{c_i\}$ 使得 $\forall i\neq j$,有 $c_i\equiv0\pmod{r_j}$,且 $c_i\equiv1\pmod{r_i}$,那么一定存在解 $x\equiv\sum a_ic_i\pmod{\prod r_i}$。

给出一种构造方法:令 $m_i=\frac{\prod r_i}{r_i}$,则 $c_i\equiv m_i\times m_i^{-1}$,其中 $m_i^{-1}$ 是 $m_i$ 模 $r_i$ 的乘法逆元(但运算结果不作取模),显然满足上述性质,这就是 Chinese Remainder Theorem 的构造本质。

阶(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}$。