数论模板汇总(下)

阅读: 评论:0

数论模板汇总(下)

数论模板汇总(下)

37.排列组合

不可重复排列数 n ! ( n − r ) ! frac{n!}{(n-r)!} (n−r)!n!​
可重复排列数 n r n^r nr
圆排列数 n ! r ( n − r ) ! frac{n!}{r(n-r)!} r(n−r)!n!​
无限多重集排列,k个不同元素 k r k^r kr
有限多重集排列,k个不同元素 n ! n 1 ! n 2 ! . . . n k ! frac{n!}{n_1!n_2!...n_k!} n1​!n2​!...nk​!n!​
无限多重集组合,k个不同元素 C r + k − 1 r C_{r+k-1}^r Cr+k−1r​

38.鸽巢原理

n+1只鸽子住n个巢,至少有一个巢里有至少2只鸽子
kn+1只鸽子住n个巢,至少有一个巢里有至少k+1只鸽子
如果将 q 1 + q 2 + . . . q n − n + 1 q_1+q_2+...q_n-n+1 q1​+q2​+...qn​−n+1个物体放入n个盒子,那么或者第1个盒子至少有 q 1 q_1 q1​个物体,或者第2个盒子至少有 q 2 q_2 q2​个物体,…,或者第n个盒子至少有 q n q_n qn​个物体
Ramsey定理:在6人(或更多)中,或者有3人,每两人都互相认识,或者有3人,每两人都不认识

39.杨辉三角与二项式定理

C n r = ( n r ) = n ! r ! ( n − r ) ! C_n^r=binom{n}{r}=frac{n!}{r!(n-r)!} Cnr​=(rn​)=r!(n−r)!n!​
杨辉三角第n+1行第r+1列数, ( 1 + x ) n (1+x)^n (1+x)n展开后第r+1项系数
( a + b ) n = ∑ r = 0 n C n r a r b n − r (a+b)^n=sumlimits_{r=0}^nC_n^ra^rb^{n-r} (a+b)n=r=0∑n​Cnr​arbn−r
C n r = C n − 1 r − 1 + C n − 1 r C_n^r=C_{n-1}^{r-1}+C_{n-1}^r Cnr​=Cn−1r−1​+Cn−1r​
C n 0 + C n 1 + . . . + C n n = 2 n C_n^0+C_n^1+...+C_n^n=2^n Cn0​+Cn1​+...+Cnn​=2n

40.组合数(递推)

#include<bits/stdc++.h>
using namespace std;
const int N = 2010, mod = 1e9 + 7;
int c[N][N];
void init(){for (int i = 0; i < N; i ++ )for (int j = 0; j <= i; j ++ )if (j==0) c[i][j] = 1;else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
int main(){int n;init();scanf("%d", &n);while (n -- ){int a, b;scanf("%d%d", &a, &b);printf("%dn", c[a][b]);}return 0;
}

41.组合数(费马小定理/预处理)

预处理 O ( n ) O(n) O(n)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 998244353;
const ll N = 1e6 + 10;
ll jc[N], jcn[N],inv[N];;
//ll ksm(ll a, ll b) {
//    ll res = 1;
//    a = a % mod;
//    while (b) {
//        if (b & 1) res = (res * a) % mod;
//        a = (a * a) % mod;
//        b >>= 1;
//    }
//    return res;
//}
//费马小定理
//ll ny(ll x) {
//    return ksm(x, mod - 2);
//}
void pre_ny(ll n, ll p) {inv[1] = 1;for (ll i = 2; i <= n; i++) inv[i] = (p - p / i) * (inv[p % i]) % p;//线性求逆元
}
ll C(ll n, ll m) {return jc[n] * jcn[m] % mod * jcn[n - m] % mod;
}
int main() {pre_ny(N, mod);jc[0] = jcn[0] = 1;for (ll i = 1; i <= N; i++) {jc[i] = (jc[i - 1] * i) % mod;jcn[i] = (jcn[i - 1] * inv[i]) % mod;}ll t, n, m;cin>>t;while (t--) {cin >> n >> m;cout<< C(n, m)<<'n';}return 0;
}

42.卢卡斯定理

对于质数 p,有
C n r ≡ C n m o d p r m o d p ⋅ C n / p r / p ( m o d p ) C_n^requiv C_{n mod p}^{r mod p}cdot C_{n/p}^{r/p}(mod p) Cnr​≡Cn mod pr mod p​⋅Cn/pr/p​(mod p)

P3807 【模板】卢卡斯定理/Lucas 定理
给定整数 n , m , p n, m, p n,m,p 的值,求出 C n + m n m o d p C_{n + m}^n bmod p Cn+mn​modp 的值。
输入数据保证 p p p 为质数。
注: C C C 表示组合数。

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll INF = 1e18;
const ll N = 1e5 + 10;
const ll mod = 1e9 + 7;
ll jc[N];
ll ksm(ll a, int b, int p) {a %= p;ll res = 1;while (b) {if (b & 1) res = (res * a) % p;a = (a * a) % p;b >>= 1;}return res;
}
ll C(int n, int r, int p) {if (r > n) return 0;return jc[n] * ksm(jc[r], p - 2, p) % p * ksm(jc[n - r], p - 2, p) % p;
}
ll lucas(int n, int r, int p) {if (r == 0) return 1;return C(n % p, r % p, p) * lucas(n / p, r / p, p) % p;
}
void solve() {int n, m, p;cin >> n >> m >> p;jc[0] = 1;for (int i = 1; i <= p; ++i) jc[i] = (jc[i - 1] * i) % p;cout << lucas(n + m, n, p) << 'n';
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;//_t = 1;cin >> _t;while (_t--) {solve();}return 0;
}

43.扩展卢卡斯定理

{ C n m m o d p 1 α 1 C n m m o d p 2 α 2 . . . . . . left{begin{aligned}C_n^m bmod {p_1^{alpha_1}} \C_n^m bmod {p_2^{alpha_2}}\ ......end{aligned} right. ⎩ ⎧​Cnm​mod p1α1​​Cnm​mod p2α2​​......​
= n ! P x m ! P y ( n − m ) ! P z P x − y − z m o d P k =frac {frac {n!}{P^{x}}}{frac {m!}{P^{y}}frac {(n-m)!}{P^{z}}}P^{x-y-z}bmod{P^k} =Pym!​Pz(n−m)!​Pxn!​​Px−y−zmodPk
= f ( n ) f ( m ) f ( n − m ) P g ( n ) − g ( m ) − g ( n − m ) m o d P k =frac {f(n)}{f(m)f(n-m)}P^{g(n)-g(m)-g(n-m)}bmod{P^k} =f(m)f(n−m)f(n)​Pg(n)−g(m)−g(n−m)modPk
f ( n ) = f ( ⌊ n P ⌋ ) ( ∏ i = 1 , i ≢ 0 ( m o d P ) P k i ) ⌊ n P k ⌋ ( ∏ i = P k ⌊ n P k ⌋ , i ≢ 0 ( m o d P ) n i ) f(n)=f(lfloor frac nPrfloor)(prodlimits_{i=1,inotequiv 0pmod {P}}^{P^k}i)^{lfloor frac n{P^k}rfloor}(prodlimits_{i=P^klfloor frac n{P^k}rfloor,inotequiv 0pmod {P}}^ni)  f(n)=f(⌊Pn​⌋)(i=1,i≡0(modP)∏Pk​i)⌊Pkn​⌋(i=Pk⌊Pkn​⌋,i≡0(modP)∏n​i)
g ( n ) = ⌊ n P ⌋ + g ( ⌊ n P ⌋ ) g(n)=lfloor frac nPrfloor+g(lfloor frac nPrfloor) g(n)=⌊Pn​⌋+g(⌊Pn​⌋)

P4720 【模板】扩展卢卡斯定理/exLucas
求 C n m m o d p {mathrm{C}}_n^m bmod{p} Cnm​modp
其中 C mathrm{C} C 为组合数。

O ( log ⁡ P n ) O(log_Pn) O(logP​n)

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
ll n, m, p;
ll prime[N], cnt, c[N];
ll ksm(ll a, ll b, ll p) {ll res = 1;while (b) {if (b & 1) res = res * a % p;a = a * a % p;b >>= 1;}return res;
}
ll exgcd(ll a, ll b, ll& x, ll& y) {if (!b) {x = 1, y = 0;return a;}ll t = exgcd(b, a % b, x, y);ll x0 = x, y0 = y;x = y0;y = x0 - a / b * y0;return t;
}
ll ny(ll n, ll p) {ll x, y;exgcd(n, p, x, y);return (x % p + p) % p;
}
ll f(ll n, ll p, ll pr) {if (n == 0) return 1;ll rou = 1, rem = 1;for (ll i = 1; i <= p; ++i) {if (i % pr) rou = rou * i % p;}rou = ksm(rou, n / p, p);for (ll i = p * (n / p); i <= n; ++i) {if (i % pr) rem = rem * (i % p) % p;}return f(n / pr, p, pr) * rou % p * rem % p;
}
ll g(ll n, ll p) {if (n < p) return 0;return g(n / p, p) + n / p;
}
ll C(ll n, ll m, ll p, ll pr) {ll fz = f(n, p, pr), fm1 = ny(f(m, p, pr), p), fm2 = ny(f(n - m, p, pr), p);ll pp = ksm(pr, g(n, pr) - g(m, pr) - g(n - m, pr), p);return fz * fm1 % p * fm2 % p * pp % p;
}
void getprime(int x) {for (ll i = 2; i * i <= x; ++i) {if (x % i == 0) {ll res = 1;while (x % i == 0) {res *= i;x /= i;}prime[++cnt] = res;c[cnt] = C(n, m, res, i);}}if (x != 1) {prime[++cnt] = x;c[cnt] = C(n, m, x, x);}
}
ll exlucas(ll n, ll m, ll p) {getprime(p);ll ans = 0;for (ll i = 1; i <= cnt; ++i) {ll m = p / prime[i], inv = ny(m, prime[i]);ans = (ans + c[i] * m % p * inv % p) % p;}return ans;
}
void solve() {cin >> n >> m >> p;cout << exlucas(n, m, p);
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;_t = 1;//cin>>_t;while (_t--) {solve();}return 0;
}

44.容斥原理

∣ A 1 ∪ A 2 ∪ . . . ∪ A n ∣ = ∑ ∣ A i ∣ − ∑ ∣ A i ∩ A j ∣ + ∑ ∣ A i ∩ A j ∩ A k ∣ + . . . + ( − 1 ) n + 1 ∣ A 1 ∩ A 2 ∩ . . . ∩ A n ∣ |A_1cup A_cup A_n|=sum|A_i|-sum|A_icap A_j|+sum|A_icap A_jcap A_k|+...+(-1)^{n+1}|A_1cap A_cap A_n| ∣A1​∪A2​∪...∪An​∣=∑∣Ai​∣−∑∣Ai​∩Aj​∣+∑∣Ai​∩Aj​∩Ak​∣+...+(−1)n+1∣A1​∩A2​∩...∩An​∣

45.卡特兰数

C n = 1 n + 1 ( 2 n n ) C_n=frac{1}{n+1}binom{2n}{n} Cn​=n+11​(n2n​)
C n = ( 2 n n ) − ( 2 n n − 1 ) C_n=binom{2n}{n}-binom{2n}{n-1} Cn​=(n2n​)−(n−12n​)
C n = C 0 C n − 1 + C 1 C n − 2 + . . . + C n − 2 C 1 + C n − 1 C 0 = ∑ C k C n − k , C 0 = 1 C_n=C_0C_{n-1}+C_1C_{n-2}+...+C_{n-2}C_1+C_{n-1}C_0=sum C_kC_{n-k},C_0=1 Cn​=C0​Cn−1​+C1​Cn−2​+...+Cn−2​C1​+Cn−1​C0​=∑Ck​Cn−k​,C0​=1
C n = 4 n − 2 n + 1 C n − 1 , C 0 = 1 C_n=frac{4n-2}{n+1}C_{n-1},C_0=1 Cn​=n+14n−2​Cn−1​,C0​=1
把n个1和n个0排成一行,使任意前k个数中1的数量总大于等于0的数量的排列数量
应用:
1.棋盘问题(路径问题)
2.括号问题(出栈序列问题)
3.二叉树问题
4.三角剖分问题:n+1条边凸多边形划分三角形,有 C n − 1 C_{n-1} Cn−1​种方案

46.第一类斯特林数

s ( n , k ) , [ n k ] : s(n,k),{nbrack k}: s(n,k),[kn​]: 把n个不同元素分配到k个圆排列里的方案数
升阶函数各项系数
[ n k ] = [ n − 1 k − 1 ] + ( n − 1 ) [ n − 1 k ] {nbrack k}={n-1brack k-1}+(n-1){n-1brack k} [kn​]=[k−1n−1​]+(n−1)[kn−1​]
s ( 0 , 0 ) = 1 s(0,0)=1 s(0,0)=1
s ( n , 0 ) = 0 s(n,0)=0 s(n,0)=0
s ( n , n ) = 1 s(n,n)=1 s(n,n)=1
s ( n , 1 ) = ( n − 1 ) ! s(n,1)=(n-1)! s(n,1)=(n−1)!
s ( n , 2 ) = ( n − 1 ) ! ∑ i = 1 n − 1 1 i s(n,2)=(n-1)!sumlimits_{i=1}^{n-1}frac{1}{i} s(n,2)=(n−1)!i=1∑n−1​i1​
s ( n , n − 1 ) = C n 2 s(n,n-1)=C_n^2 s(n,n−1)=Cn2​
s ( n , n − 2 ) = 2 C n 3 + 3 C n 4 s(n,n-2)=2C_n^3+3C_n^4 s(n,n−2)=2Cn3​+3Cn4​
∑ k = 0 n s ( n , k ) = n ! sumlimits_{k=0}^ns(n,k)=n! k=0∑n​s(n,k)=n!

47.第二类斯特林数

S ( n , k ) , { n k } : S(n,k),{nbrace k}: S(n,k),{kn​}: 把n个不同元素拆分成k个集合的方案数
{ n k } = { n − 1 k − 1 } + k { n − 1 k } {nbrace k}={n-1brace k-1}+k{n-1brace k} {kn​}={k−1n−1​}+k{kn−1​}
S ( n , m ) = 1 m ! ∑ k = 0 m ( − 1 ) k ( m k ) ( m − k ) n S(n,m)=frac{1}{m!}sumlimits_{k=0}^m(-1)^kbinom{m}{k}(m-k)^n S(n,m)=m!1​k=0∑m​(−1)k(km​)(m−k)n
S ( n , 0 ) = 0 n S(n,0)=0^n S(n,0)=0n
S ( n , n ) = 1 S(n,n)=1 S(n,n)=1
S ( n , 1 ) = 1 S(n,1)=1 S(n,1)=1
S ( n , 2 ) = 2 n − 1 − 1 S(n,2)=2^{n-1}-1 S(n,2)=2n−1−1
S ( n , n − 1 ) = C n 2 S(n,n-1)=C_n^2 S(n,n−1)=Cn2​
S ( n , n − 2 ) = C n 3 + 3 C n 4 S(n,n-2)=C_n^3+3C_n^4 S(n,n−2)=Cn3​+3Cn4​
∑ k = 0 n S ( n , k ) = B n , B n sumlimits_{k=0}^nS(n,k)=B_n,B_n k=0∑n​S(n,k)=Bn​,Bn​是贝尔数
∑ k = 0 n { n k } [ k m ] = ∑ k = 0 n [ n k ] { k m } sumlimits_{k=0}^n{nbrace k}{kbrack m}=sumlimits_{k=0}^n{nbrack k}{kbrace m} k=0∑n​{kn​}[mk​]=k=0∑n​[kn​]{mk​}

48.贝尔数

B n B_n Bn​的含义是基数为 n 的集合划分成非空集合的划分数
B 0 = 1 B_0=1 B0​=1
B n + 1 = ∑ k = 0 n ( n k ) B k B_{n+1}=sumlimits_{k=0}^nbinom{n}{k}B_k Bn+1​=k=0∑n​(kn​)Bk​
B n = ∑ k = 0 n S ( n , k ) B_n=sumlimits_{k=0}^nS(n,k) Bn​=k=0∑n​S(n,k)
第一行第一项为 1 ( a 1 , 1 = 1 ) (a_{1,1}=1) (a1,1​=1);
对于 n>1,第 n 行第一项等于第 n-1 行的第 n - 1 项 ( a n , 1 = a n − 1 , n − 1 ) (a_{n,1}=a_{n-1,n-1}) (an,1​=an−1,n−1​);
对于 m,n>1,第 n 行的第 m 项等于它左边和左上角两个数之和 ( a n , m = a n , m − 1 + a n − 1 , m − 1 ) (a_{n,m}=a_{n,m-1}+a_{n-1,m-1}) (an,m​=an,m−1​+an−1,m−1​)
每行的首项是贝尔数。

49.错位排列

D n = ( n − 1 ) ( D n − 1 + D n − 2 ) D_n=(n-1)(D_{n-1}+D_{n-2}) Dn​=(n−1)(Dn−1​+Dn−2​)
D n = n ! ∑ k = 0 n ( − 1 ) k k ! D_n=n!sumlimits_{k=0}^nfrac{(-1)^k}{k!} Dn​=n!k=0∑n​k!(−1)k​

50.Burnside定理

置换的合成运算 g ∘ f ( k ) = g ( f ( k ) ) gcirc f(k)=g(f(k)) g∘f(k)=g(f(k))
置换的逆 f − 1 ∘ f = τ f^{-1}circ f=tau f−1∘f=τ, τ tau τ为恒等置换
设G是S的置换群,f是G中的一个置换,设 λ ( f ) lambda(f) λ(f)为置换f中不变元的个数,则置换群G的着色方法数为 1 ∣ G ∣ ∑ f ∈ G ∣ λ ( f ) ∣ frac{1}{|G|}sumlimits_{fin G}|lambda(f)| ∣G∣1​f∈G∑​∣λ(f)∣

P1446 [HNOI2008] Cards
小春现在很清闲,面对书桌上的 n n n 张牌,他决定给每张牌染色,目前小春拥有 3 3 3 种颜色:红色,蓝色,绿色。他询问 Sun 有多少种染色方案,Sun 很快就给出了答案。
进一步,小春要求染出 S r S_r Sr​ 张红色, S b S_b Sb​ 张蓝色, S g S_g Sg​ 张绿色。他又询问有多少种方案,Sun 想了一下,又给出了正确答案。最后小春发明了 m m m 种不同的洗牌法,这里他又问 Sun 有多少种不同的染色方案。两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种。
Sun 发现这个问题有点难度,决定交给你,由于答案可能很大,你只需要求出答案对于 P P P 取模的结果。 保证 P P P 为一个质数。

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
int sr, sb, sg, n, m, p, ans;
int a[100], vis[100], siz[100], dp[25][25][25];
ll ksm(ll a, ll b) {a %= p;ll res = 1;while (b) {if (b & 1) res = res * a % p;a = a * a % p;b >>= 1;}return res;
}
int calc() {memset(dp, 0, sizeof(dp));memset(vis, 0, sizeof(vis));int cnt = 0;for (int i = 1; i <= n; ++i) {if (!vis[i]) {int p = i, len = 0;while (!vis[p]) {len++;vis[p] = 1;p = a[p];}siz[++cnt] = len;}}dp[0][0][0] = 1;for (int i = 1; i <= cnt; ++i) {for (int r = sr; r>=0; --r) {for (int b = sb; b>=0; --b) {for (int g = sg; g>=0; --g) {if (r >= siz[i]) dp[r][b][g] = (dp[r][b][g] + dp[r - siz[i]][b][g]) % p;if (b >= siz[i]) dp[r][b][g] = (dp[r][b][g] + dp[r][b - siz[i]][g]) % p;if (g >= siz[i]) dp[r][b][g] = (dp[r][b][g] + dp[r][b][g - siz[i]]) % p;}}}}return dp[sr][sb][sg];
}
void solve() {cin >> sr >> sb >> sg >> m >> p;n = sr + sb + sg;for (int i = 1; i <= m; ++i) {for (int j = 1; j <= n; ++j) {cin >> a[j];}ans = (ans + calc()) % p;}for (int i = 1; i <= n; ++i) a[i] = i;ans = (ans + calc()) % p;cout << ans * ksm(m + 1, p - 2) % p;
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;_t = 1;//cin>>_t;while (_t--) {solve();}return 0;
}

51.Pólya 定理

任何一种置换都能表示成若干互不相交的循环的乘积。
在一种置换中,用 λ i ( f ) lambda_i(f) λi​(f) 表示长度为 i 的循环的个数,用 λ ( f ) lambda(f) λ(f)表示 f ∈ G fin G f∈G中循环的个数。
设 G = { f 1 , f 2 , . . . , f n } G={f_1,f_2,...,f_n} G={f1​,f2​,...,fn​}是 S n S_n Sn​是置换群,用 m 种颜色对 n 个对象着色,G的着色方法数为 1 ∣ G ∣ ∑ f ∈ G m λ ( f ) = 1 ∣ G ∣ ∑ f ∈ G m λ 1 ( f ) + λ 2 ( f ) + . . . + λ n ( f ) frac{1}{|G|}sumlimits_{fin G}m^{lambda(f)}=frac{1}{|G|}sumlimits_{fin G}m^{lambda_1(f)+lambda_2(f)+...+lambda_n(f)} ∣G∣1​f∈G∑​mλ(f)=∣G∣1​f∈G∑​mλ1​(f)+λ2​(f)+...+λn​(f)
第 i 个旋转的循环节数为 g c d ( n , i ) , 0 ≤ i < n gcd(n,i),0le i<n gcd(n,i),0≤i<n
若 n 为偶数,经过多边形顶点的对称轴有n/2个,即n/2种置换,每种置换方案有n/2+1个循环节;不经过顶点的对称轴有n/2个,每种置换方案有n/2个循环节
若 n 为奇数,对称轴都经过顶点,有n种置换,每种置换有n/2+1个循环节

P4980 【模板】Pólya 定理
给定一个 n n n 个点, n n n 条边的环,有 n n n 种颜色,给每个顶点染色,问有多少种本质不同的染色方案,答案对 1 0 9 + 7 10^9+7 109+7 取模
注意本题的本质不同,定义为:只需要不能通过旋转与别的染色方案相同

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
ll getphi(ll n) {ll res = n;for (ll i = 2; i*i<=n; ++i) {if (n % i == 0) {res = res / i * (i - 1);while (n % i == 0) n /= i;}}if (n > 1) res = res / n * (n - 1);return res;
}
ll ksm(ll a, ll b) {a %= mod;ll res = 1;while (b) {if (b & 1) res = (res * a) % mod;a = (a * a) % mod;b >>= 1;}return res;
}
void solve() {ll n,ans=0;cin >> n;for (ll i = 1; i * i <= n; ++i) {if (n % i == 0) {ans = (ans + getphi(i) * ksm(n, n / i - 1)) % mod;if (i * i != n) ans = (ans + getphi(n / i) * ksm(n, i - 1)) % mod;}}cout << ans << 'n';
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;//_t = 1;cin>>_t;while (_t--) {solve();}return 0;
}

52.生成函数

生成函数的定义: g ( x ) = a 0 + a 1 x + a 2 x 2 + a 3 x 3 + . . . g(x)=a_0+a_1x+a_2x^2+a_3x^3+... g(x)=a0​+a1​x+a2​x2+a3​x3+....称g(x)是序列 a 0 , a 1 , a 2 , . . . a_0,a_1,a_2,... a0​,a1​,a2​,...的生成函数,x 充当形式参数没有意义。
普通生成函数:k 种元素的多重集合的 r 组合数(有限和无限多重集都可以)
指数生成函数:k 种元素的多重集合的 r 排列数(有限和无限多重集都可以)

列出式子,有 n 项,每项代表一个种类的限制(一个括号代表一项),共取 m 个,生成函数为 g ( x ) = ( 1 + x + x 2 + … ) ( 1 + x 2 + x 4 + … ) ( 1 + x 3 + x 6 + … ) … g(x)=(1+x+x^2+dots)(1+x^2+x^4+dots)(1+x^3+x^6+dots)dots g(x)=(1+x+x2+…)(1+x2+x4+…)(1+x3+x6+…)…计算 x m x^m xm 的系数,化为分式,二项式展开。

  1. HDU - 2152 Fruit (普通生成函数)
    有 n 种水果,每种水果出现的次数在 [ a i , b i ] [a_i,b_i] [ai​,bi​] 之间,问一共买 m 个水果有多少种购买方案?
    ( x a 1 + ⋯ + x b 1 ) ( x a 2 + ⋯ + x b 2 ) … ( x a n + ⋯ + x b n ) (x^{a_1}+dots+x^{b_1})(x^{a_2}+dots+x^{b_2})dots(x^{a_n}+dots+x^{b_n}) (xa1​+⋯+xb1​)(xa2​+⋯+xb2​)…(xan​+⋯+xbn​)对这个生成函数求 x m x^m xm 的系数
  2. HDU - 1521 排列组合 (指数生成函数)
    有 n 种物品,每种物品的数量为 a i a_i ai​ ,问取 m 个物品的排列数
    ( 1 + x + x 2 2 ! + ⋯ + x a 1 a 1 ! ) ( 1 + x + x 2 2 ! + ⋯ + x a 2 a 2 ! ) … ( 1 + x + x 2 2 ! + ⋯ + x a n a n ! ) (1+x+frac {x^2}{2!}+dots+frac {x^{a_1}}{a_1!})(1+x+frac {x^2}{2!}+dots+frac {x^{a_2}}{a_2!})dots(1+x+frac {x^2}{2!}+dots+frac {x^{a_n}}{a_n!}) (1+x+2!x2​+⋯+a1​!xa1​​)(1+x+2!x2​+⋯+a2​!xa2​​)…(1+x+2!x2​+⋯+an​!xan​​)对这个式子求 x m x^m xm 的系数
  3. HDU - 1028 Ignatius and the Princess III (普通生成函数)
    将整数 n 拆分成正整数相加的形式,问有几种组合
    每一个小于 n 的正整数都有可能组成。共有 n 个因子,可以得到生成函数
    g ( x ) = ( 1 + x + x 2 + … ) ( 1 + x 2 + x 4 + … ) ( 1 + x 3 + x 6 + … ) … g(x)=(1+x+x^2+dots)(1+x^2+x^4+dots)(1+x^3+x^6+dots)dots g(x)=(1+x+x2+…)(1+x2+x4+…)(1+x3+x6+…)…
    x n x^n xn的系数就是所求的组合方式
  4. HDU - 1085 Holding Bin-Laden Captive! (普通生成函数)
    由面值为1、2、5的硬币不能组成的最小面值是多少。
    可以得到生成函数 g ( x ) = ( 1 + x + x 2 + … ) ( 1 + x 2 + x 4 + … ) ( 1 + x 5 + x 10 + … ) g(x)=(1+x+x^2+dots)(1+x^2+x^4+dots)(1+x^5+x^{10}+dots) g(x)=(1+x+x2+…)(1+x2+x4+…)(1+x5+x10+…)从小到大遍历系数,为 0 的那一项就是不能组成的
  5. HDU - 2189 悼念512汶川大地震遇难同胞——来生一起走 (普通生成函数)
    把n个人分成几个小组。每个小组的人数必须是素数
    用素数组成n,但是不知道用具体多少个素数。每一个小于等于 n 的素数都是一个因子。可以得到生成函数: g ( x ) = ( 1 + x 2 + x 4 + x 6 + … ) ( 1 + x 3 + x 6 + … ) ( 1 + x 5 + x 10 + … ) x n g(x)=(1+x^2+x^4+x^6+dots)(1+x^3+x^{6}+dots)(1+x^5+x^{10}+dots) x^n g(x)=(1+x2+x4+x6+…)(1+x3+x6+…)(1+x5+x10+…) xn的系数就是这个组合数的答案
  6. BZOJ3028: 食物(普通生成函数 + 推导 + 欧拉降幂)
    明明这次又要出去旅游了,和上次不同的是,他这次要去宇宙探险!我们暂且不讨论他有多么NC,他又幻想了他应该带一些什么东西。理所当然的,你当然要帮他计算携带N件物品的方案数。他这次又准备带一些受欢迎的食物,如:蜜桃多啦,鸡块啦,承德汉堡等等。每种食物的限制如下:
    (1)承德汉堡:偶数个(2)可乐:0个或1个(3)鸡腿:0个,1个或2个(4)蜜桃多:奇数个(5)鸡块:4的倍数个(6)包子:0个,1个,2个或3个(7)土豆片炒肉:不超过一个。(8)面包:3的倍数个
    很明显示生成函数的题,并且考虑的是组合数,可以得到生成函数:思路:很明显示生成函数的题,并且考虑的是组合数
    可以得到生成函数: g ( x ) = ( 1 + x 2 + … ) ( 1 + x ) ( 1 + x + x 2 ) ( x + x 3 + … ) ( 1 + x 4 + x 8 + … ) ( 1 + x + x 2 + x 3 ) ( 1 + x ) ( 1 + x 3 + x 6 + … ) = 1 1 − x 2 ( 1 + x ) 1 − x 3 1 − x x 1 1 − x 2 1 1 − x 4 ( 1 − x 4 1 − x ) ( 1 + x ) 1 1 − x 3 = x ( 1 − x ) 4 = ∑ n = 0 ∞ C n + 4 − 1 3 x n + 1 = ∑ n = 0 ∞ C n + 2 3 x n g(x)=(1+x^2+dots )(1+x)(1+x+x^2)(x+x^3+dots)(1+x^4+x^8+dots)(1+x+x^2+x^3)(1+x)(1+x^3+x^6+dots)=frac 1{1-x^2}(1+x)frac {1-x^3}{1-x}xfrac 1{1-x^2}{frac {1}{1-x^4}}(frac {1-x^4}{1-x})(1+x)frac 1{1-x^3}=frac x{(1-x)^4}=sum_{n=0}^{infty}C_{n+4-1}^3x^{n+1}=sum_{n=0}^{infty}C_{n+2}^3x^n g(x)=(1+x2+…)(1+x)(1+x+x2)(x+x3+…)(1+x4+x8+…)(1+x+x2+x3)(1+x)(1+x3+x6+…)=1−x21​(1+x)1−x1−x3​x1−x21​1−x41​(1−x1−x4​)(1+x)1−x31​=(1−x)4x​=∑n=0∞​Cn+4−13​xn+1=∑n=0∞​Cn+23​xn
    因此,答案就是 a n = C n + 2 3 a_n=C_{n+2}^3 an​=Cn+23​
  7. 2019 ICPC上海网络赛 E. Counting Sequences II (指数生成函数 + 推导)
    给定n个位置,对于每一个数 a i ​ a_i​ ai​​,都满足 1 ≤ a i ≤ m 1 ≤ a_i ≤ m 1≤ai​≤m,并且如果 a i a_i ai​是偶数的话, a i a_i ai​出现的次数是偶数次,求排列的个数
    求的是排列,所以是指数型生成函数。在[1,m]的范围内,相当于有m个因子,每个因子分别代表对1 ,2 ,3 ,4 , … ,m各自的限制。其中偶数有 f l o o r ( m 2 ) floor(frac m2) floor(2m​) 个,奇数有 m − f l o o r ( m 2 ) m-floor(frac m2) m−floor(2m​) ,设 t = f l o o r ( m 2 ) t=floor(frac m2) t=floor(2m​) ,可以得到指数型生成函数
    g ( x ) = ( 1 + x + x 2 2 ! + x 3 3 ! + … ) m − t ( 1 + x 2 2 ! + x 4 4 ! + … ) t g(x)=(1+x+frac {x^2}{2!}+frac {x^3}{3!}+dots)^{m-t}(1+frac {x^2}{2!}+frac {x^4}{4!}+dots)^{t} g(x)=(1+x+2!x2​+3!x3​+…)m−t(1+2!x2​+4!x4​+…)t
    化简可得: g ( x ) = e x ( m − t ) ( e x + e − x 2 ) t = e x ( m − t ) ∑ i = 0 t C t i e x ( t − i ) e − x i 2 t = ∑ i = 0 t C t i e ( m − 2 i ) x 2 t = ∑ n = 0 ∑ i = 0 t C t i ( m − 2 i ) n 2 t x n n ! g(x)=e^{x(m-t)}(frac {e^x+e^{-x}}2)^t=frac{e^{x(m-t)}sum_{i=0}^tC_t^ie^{x(t-i)}e^{-xi}}{2^t}=frac {sum_{i=0}^tC_t^ie^{(m-2i)x}}{2^t}=sumlimits_{n=0}frac{sum_{i=0}^tC_t^i{(m-2i)^n}}{2^t}frac {x^n}{n!} g(x)=ex(m−t)(2ex+e−x​)t=2tex(m−t)∑i=0t​Cti​ex(t−i)e−xi​=2t∑i=0t​Cti​e(m−2i)x​=n=0∑​2t∑i=0t​Cti​(m−2i)n​n!xn​
    因此可以得到 a n = ∑ i = 0 t C t i ( m − 2 i ) n 2 t a_n=frac{sum_{i=0}^tC_t^i{(m-2i)^n}}{2^t} an​=2t∑i=0t​Cti​(m−2i)n​ , a n a_n an​ 就是答案
  8. 硬币兑换问题
    将n元钱全部兑换成1元和2元,有多少种兑换方法
    g ( x ) = ( 1 + x + x 2 + … ) ( 1 + x 2 + x 4 + … ) g(x)=(1+x+x^2+dots)(1+x^2+x^4+dots) g(x)=(1+x+x2+…)(1+x2+x4+…)
  9. 组合选取问题
    一副三色纸牌共 32 张其中红黄蓝每种颜色的牌各 10 张编号分别是1,2,3,…,10;另有大小王各一张,编号均为 0 。从这副牌中取出若干张牌,然后按如下规则计算分值:每张编号为 k 的牌计为 2 k 2^k 2k 分若它们的分值之和等于 2004 就称这些牌为一个“好”牌组。试求“好”牌组的个数
    g ( x ) = ( 1 + x 2 0 ) 2 ( 1 + x 2 1 ) 3 … ( 1 + x 2 10 ) 3 g(x)=(1+x^{2^0})^2(1+x^{2^1})^3dots(1+x^{2^{10}})^3 g(x)=(1+x20)2(1+x21)3…(1+x210)3
  10. 有 n 个标号为 1 , 2 , ⋯ , n 的球,放到 m 个无标号盒子 (盒内顺序有标号),且每个盒子球数不超过 k ,求方案数对 998244353 取模。
    考虑每个盒子内球的生成函数 ∑ i = 1 k x i sumlimits_{i = 1} ^ {k}x ^ i i=1∑k​xi ,那么 m 个盒子的生成函数就为 ( ∑ i = 1 k x i ) m left( sumlimits_{i = 1} ^ {k}x ^ iright) ^ m (i=1∑k​xi)m,那么方案数就为第 n 项系数。由于球带标号,所以需要对答案全排列,也就是乘 n! ,又由于盒子不带标号,所以要对答案除 m! ,那么答案为 n ! m ! × [ x n ] ( ∑ i = 1 k x i ) m frac{n!}{m!} times [x ^ n]left( sumlimits_{i = 1} ^ {k}x ^ iright) ^ m m!n!​×[xn](i=1∑k​xi)m

1 ( 1 − x ) n = ∑ k = 0 ∞ C n + k − 1 k x k frac{1}{(1-x)^n}=sumlimits_{k=0}^infty C_{n+k-1}^kx^k (1−x)n1​=k=0∑∞​Cn+k−1k​xk
1 1 − x = 1 + x + x 2 + x 3 + . . . frac{1}{1-x}=1+x+x^2+x^3+... 1−x1​=1+x+x2+x3+...
1 1 − x 6 = 1 + x 6 + x 12 + . . . frac{1}{1-x^6}=1+x^6+x^{12}+... 1−x61​=1+x6+x12+...
1 − x 6 1 − x = 1 + x + x 2 + x 3 + x 4 + x 5 frac{1-x^6}{1-x}=1+x+x^2+x^3+x^4+x^5 1−x1−x6​=1+x+x2+x3+x4+x5
x ( 1 − x ) 2 = x + 2 x 2 + 3 x 3 + . . . frac{x}{(1-x)^2}=x+2x^2+3x^3+... (1−x)2x​=x+2x2+3x3+...
e x = 1 + 1 1 ! x + 1 2 ! x 2 + 1 3 ! x 3 + . . . e^x=1+frac{1}{1!}x+frac{1}{2!}x^2+frac{1}{3!}x^3+... ex=1+1!1​x+2!1​x2+3!1​x3+...
e 2 x = 1 + 1 1 ! 2 x + 1 2 ! ( 2 x ) 2 + 1 3 ! ( 2 x ) 3 + . . . e^{2x}=1+frac{1}{1!}2x+frac{1}{2!}(2x)^2+frac{1}{3!}(2x)^3+... e2x=1+1!1​2x+2!1​(2x)2+3!1​(2x)3+...

53.康托展开

P5367 【模板】康托展开
对于一个1到n的排列{a1​ ,a2​ ,⋯,an​ },比它小的排列有 ∑ i = 1 n s u m a i × ( n − i ) ! sumlimits_{i=1}^nsum_{a_i}times(n-i)! i=1∑n​sumai​​×(n−i)!个
s u m a i sum_{a_i} sumai​​为在 ai 后面的元素里比它小的元素个数,即 ∑ j = 1 n ( a j ​ < a i ) sumlimits_{j=1}^n(a_j​<a_i) j=1∑n​(aj​​<ai​),树状数组求解
逆康托展开
类似于进制转换,不断 %(n-i)! ,/(n-i)!就可以得到sum数组,然后就可以还原出原排列。

54.巴什博弈

HDU - 1846 Brave Game
各位勇敢者要玩的第一个游戏是什么呢?很简单,它是这样定义的:
1、 本游戏是一个二人游戏;
2、 有一堆石子一共有n个;
3、 两人轮流进行;
4、 每走一步可以取走1…m个石子;
5、 最先取光石子的一方为胜;
如果游戏的双方使用的都是最优策略,请输出哪个人能赢。

结论:被(m+1)整除,先手败

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll INF = 1e18;
const ll N = 1e5 + 10;
void solve() {int n;cin >> n;for (int i = 1; i <= n; ++i) {int x, y;cin >> x >> y;if (x % (y + 1)==0) cout << "secondn";else cout << "firstn";}
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;_t = 1;//cin >> _t;while (_t--) {solve();}return 0;
}

55.nim博弈

P2197 【模板】nim 游戏
甲,乙两个人玩 nim 取石子游戏。
nim 游戏的规则是这样的:地上有 n n n 堆石子(每堆石子数量小于 1 0 4 10^4 104),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这 n n n 堆石子的数量,他想知道是否存在先手必胜的策略。

结论:异或和为0,先手败

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll INF = 1e18;
const ll N = 1e5 + 10;
void solve() {int ans = 0, n;cin >> n;for (int i = 1; i <= n; ++i) {int a;cin >> a;ans ^= a;}if (ans) cout << "Yesn";else cout << "Non";
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;//_t = 1;cin>>_t;while (_t--) {solve();}return 0;
}

56.阶梯博弈

AcWing 892. 台阶-Nim游戏
现在,有一个n级台阶的楼梯,每级台阶上都有若干个石子,其中第i级台阶上有 a i a_i ai​个石子(i≥1)。
两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。
已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。

结论:当奇数级阶梯的石子数量异或和为0,先手必败,否则先手必胜。

57.威佐夫博弈

P2252 [SHOI2002]取石子游戏|【模板】威佐夫博弈
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

结论:等于(b-a)*1.618,先手败

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll INF = 1e18;
const ll N = 1e5 + 10;
void solve() {int a, b;cin >> a >> b;double temp = (sqrt(5) + 1) / 2;if (a > b) swap(a, b);if (a == int((b - a) * temp)) cout << 0;else cout << 1;
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;_t = 1;//cin >> _t;while (_t--) {solve();}return 0;
}

58.斐波那契博弈

有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下:
1)先手不能在第一次把所有的石子取完,至少取1颗;
2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍。
约定取走最后一个石子的人为赢家,求必败态。

结论:当n为斐波那契数时,先手必败。

59.P-position与N-positon

P-position为前一个玩家的必胜位置,N-position为下一个玩家的必胜位置

60.图游戏与SG函数

sg(x)等于x所有后缀sg值中未出现过的最小非负整数
SG函数实现巴什博弈,sg(x)=0的点是必败点

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e3 + 10;
int n, m, sg[N], s[N];
void getsg() {memset(sg, 0, sizeof(sg));for (int i = 1; i <= n; ++i) {memset(s, 0, sizeof(s));for (int j = 1; j <= m && i >= j; ++j) s[sg[i - j]] = 1;for (int j = 0; j <= n; ++j) {if (!s[j]) {sg[i] = j;break;}}}
}
void solve() {cin >> n >> m;getsg();if (sg[n]) cout << "firstn";else cout << "secondn";
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int _t;//_t = 1;cin>>_t;while (_t--) {solve();}return 0;
}

本文发布于:2024-01-27 20:50:00,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17063597992555.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数论   模板
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23