逆元 模为素数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 constexpr int mod = 998244353 ;ll qpow (ll a, ll n) { ll res = 1 ; while (n) { if (n & 1 ) res = res * a % mod; a = a * a % mod; n >>= 1 ; } return res; } int inv (int n) { return qpow (n, mod - 2 ); }
非固定模数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ll gcd (ll a, ll b) { return b ? gcd (b, a % b) : a; } ll exgcd (ll a, ll b, ll& x, ll& y) { if (b == 0 ) return x = 1 , y = 0 , a; ll d = exgcd (b, a % b, y, x); y -= (a / b) * x; return d; } auto exexgcd (ll a, ll b, ll c) { ll d = gcd (a, b); if (c % d) return pair (-1 , -1 ); ll x, y; a /= d, b /= d, c /= d; exgcd (a, b, x, y); x = ((x * c % b) + b * d) % b; y = (c - a * x) / b; return pair (x, y); } int mod = 123456 ;ll inv (ll a) { return liEq (a, mod, 1 ); }
组合数C n m = n ( n − 1 ) ⋯ ( n − m + 1 ) m ( m − 1 ) ⋯ 1 C n m = n − m + 1 m C n m − 1 k C n k = n C n − 1 k − 1 \begin{aligned} \operatorname{C}_{n}^{m} &= \frac{ n (n-1) \cdots (n-m+1) } { m (m-1) \cdots 1} \\ \operatorname{C}_{n}^{m} &= \frac{n-m+1}{m}C_{n}^{m-1} \\ k\operatorname{C}_{n}^{k} &= n\operatorname{C}_{n-1}^{k-1} \\ \end{aligned} C n m C n m k C n k = m ( m − 1 ) ⋯ 1 n ( n − 1 ) ⋯ ( n − m + 1 ) = m n − m + 1 C n m − 1 = n C n − 1 k − 1
杨辉三角二维递推 (使用于n n n 较小或模数不固定)
C n m = C n − 1 m + C n − 1 m − 1 C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1} C n m = C n − 1 m + C n − 1 m − 1
1 2 3 4 5 6 7 8 ll C[N][N]; void init (int n) { for (int i = 0 ; i <= n; ++i) { C[i][0 ] = C[i][i] = 1 ; for (int j = 1 ; j < i; ++j) C[i][j] = (C[i - 1 ][j - 1 ] + C[i - 1 ][j]) % mod; } }
在时间Θ ( n 2 ) \Theta(n^2) Θ ( n 2 ) 、空间Θ ( n 2 ) \Theta(n^2) Θ ( n 2 ) 内计算C 0 0 ∼ C n n C_0^0 \sim C_n^n C 0 0 ∼ C n n 。
预处理阶乘 (万用方法,适用于n n n 较大)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 constexpr int mod = 998244353 ;constexpr int N = 1e6 + 8 ;ll fac[N], ifac[N]; ll qpow (ll a, ll n) { ll res = 1 ; while (n) { if (n & 1 ) res = res * a % mod; a = a * a % mod; n >>= 1 ; } return res; } ll inv (ll n) { return qpow (n, mod - 2 ); } void init (int n) { fac[0 ] = ifac[0 ] = 1 ; for (int i = 1 ; i <= n; i++) { fac[i] = fac[i - 1 ] * i % mod; } ifac[n] = inv (fac[n]); for (int i = n; i > 0 ; i--) { ifac[i - 1 ] = ifac[i] * i % mod; } } ll C (int n, int m) { if (n < m || m < 0 ) return 0 ; return fac[n] * ifac[m] % mod * ifac[n - m] % mod; } ll A (int n, int m) { return fac[n] * ifac[n - m] % mod; }
在时空复杂度Θ ( n ) \Theta(n) Θ ( n ) 内计算C 0 0 ∼ C n n \operatorname{C}_{0}^{0} \sim \operatorname{C}_{n}^{n} C 0 0 ∼ C n n 。
卢卡斯定理 (适用于p p p 较小)
对于m , n m,n m , n 和素数p p p ,C m n ≡ ∏ i = 0 k C m i n i ( m o d p ) C_m^n\equiv\prod_{i=0}^{k}C_{m_i}^{n_i}\pmod{p} C m n ≡ ∏ i = 0 k C m i n i ( m o d p ) ,其中m = m k p k + ⋯ + m 1 p + m 0 , n = n k p k + ⋯ + n 1 p + n 0 m=m_kp^k+\cdots +m_1p+m_0,~n=n_kp^k+\cdots +n_1p+n_0 m = m k p k + ⋯ + m 1 p + m 0 , n = n k p k + ⋯ + n 1 p + n 0 是m m m 和n n n 的p p p 进制展开。
C m n ≡ C m m o d p n m o d p ⋅ C ⌊ m / p ⌋ ⌊ n / p ⌋ ( m o d p ) C_m^n\equiv C_{m\bmod p}^{n \bmod p}\cdot C_{\lfloor m/p\rfloor}^{\lfloor n/p\rfloor}\pmod{p} C m n ≡ C m m o d p n m o d p ⋅ C ⌊ m / p ⌋ ⌊ n / p ⌋ ( m o d p )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ll fac[N]; void dofac (int n, int p) { fac[0 ] = fac[1 ] = 1 ; for (int i = 2 ; i < n; ++i) fac[i] = fac[i - 1 ] * i % p; } ll inv[N]; ll doInv (ll a, ll p) { a %= p; if (a == 0 ) return -1 ; if (a == 1 ) return 1 ; if (inv[a]) return inv[a]; return inv[a] = (p - p / a) * doInv (p % a, p) % p; } ll C (ll n, ll m, ll p) { return n < m ? 0 : fac[n] * doInv (fac[m], p) % p * doInv (fac[n - m], p) % p; } ll lucas (ll n, ll m, ll p) { return m == 0 ? 1 : lucas (n / p, m / p, p) * C (n % p, m % p, p) % p; }
时间复杂度Θ ( p ) \Theta(p) Θ ( p ) 。
jiangly 组合数 (待修改)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 struct Comb { int n; std::vector<ll> _fac; std::vector<ll> _invfac; std::vector<ll> _inv; Comb () : n{0 }, _fac{1 }, _invfac{1 }, _inv{0 } {} Comb (int n) : Comb () { init (n); } void init (int m) { if (m <= n) return ; _fac.resize (m + 1 ); _invfac.resize (m + 1 ); _inv.resize (m + 1 ); for (int i = n + 1 ; i <= m; i++) { _fac[i] = _fac[i - 1 ] * i; } _invfac[m] = _fac[m].inv (); for (int i = m; i > n; i--) { _invfac[i - 1 ] = _invfac[i] * i; _inv[i] = _invfac[i] * _fac[i - 1 ]; } n = m; } Z fac (int m) { if (m > n) init (2 * m); return _fac[m]; } Z invfac (int m) { if (m > n) init (2 * m); return _invfac[m]; } Z inv (int m) { if (m > n) init (2 * m); return _inv[m]; } Z binom (int n, int m) { if (n < m || m < 0 ) return 0 ; return fac (n) * invfac (m) * invfac (n - m); } } comb;
例题 2024 杭电多校 9001 - 树异或价值[[…/contests/2024杭电多校/2024-08-16:2024“钉耙编程”中国大学生算法设计超级联赛(9)|2024-08-16:2024“钉耙编程”中国大学生算法设计超级联赛(9)]]
题意 求满足如下条件的a a a 数组的数量:
∑ i = 1 n ∑ j = 1 n ( a i ⊕ a j ) × dep LCA ( i , j ) \sum\limits_{i=1}^n \sum\limits_{j=1}^n\left(a_i \oplus a_j\right) \times \operatorname{dep}_{\operatorname{LCA}(i, j)} i = 1 ∑ n j = 1 ∑ n ( a i ⊕ a j ) × d e p L C A ( i , j ) 最大;0 ⩽ a i ⩽ 2 k − 1 0 \leqslant a_{i} \leqslant 2^{k}-1 0 ⩽ a i ⩽ 2 k − 1 。思路 每位情况独立,现设k = 1 k=1 k = 1 。
原式等价于∑ x = 1 n ∑ i , j ∈ subtree ( x ) ( a i ⊕ a j ) \sum\limits_{x=1}^n \sum\limits_{i,j \in \operatorname{subtree}(x)} \left(a_i \oplus a_j\right) x = 1 ∑ n i , j ∈ s u b t r e e ( x ) ∑ ( a i ⊕ a j ) ,表示树上所有点的子树内两两之间的异或值之和的和。这就将奇怪的问题转化为 子树问题 ,满足树形 DP 要求。
设f u , d f_{u,d} f u , d 表示填完u u u 的子树后0 0 0 和1 1 1 的数量差为d d d 的方案数。由于a i ∈ { 0 , 1 } a_i \in\{0,1\} a i ∈ { 0 , 1 } ,希望子树内0 0 0 和1 1 1 的数量尽量接近。如果子树大小为偶数,则希望数量差为0 0 0 ,只需考虑f u , 0 f_{u,0} f u , 0 ,如果子树大小为奇数,希望是± 1 \pm 1 ± 1 ,且有f u , 1 = f u , − 1 f_{u,1}=f_{u,-1} f u , 1 = f u , − 1 。因此我们 把第二维省略 ,设f u = f u , 0 f_{u}=f_{u,0} f u = f u , 0 或f u = f u , 1 f_{u}=f_{u,1} f u = f u , 1 。也就是说 只考虑0 \pmb0 0 0 不比1 \pmb1 1 1 少的情形 。
设u u u 的子节点的子树中大小为奇数的儿子的数量有g u g_{u} g u 个,不难发现g u \pmb {g_{u}} g u g u 与u \pmb u u u 子树大小的奇偶性相反 。分类讨论:
如果g u g_{u} g u 为奇数,为了使得0 0 0 和1 1 1 的数量恰好相等,
如果u u u 选择1 1 1 ,则需要在u u u 的子节点v v v 中选择g u − 1 2 \frac{g_{u}-1}{2} 2 g u − 1 个1 1 1 和g u + 1 2 \frac{g_{u}+1}{2} 2 g u + 1 个0 0 0 ; 如果u u u 选择0 0 0 ,则需要选择g u − 1 2 \frac{g_{u}-1}{2} 2 g u − 1 个0 0 0 和g u + 1 2 \frac{g_{u}+1}{2} 2 g u + 1 个1 1 1 。 这种情况下,总共有h u = 2 C g u g u / 2 h_{u}=2\operatorname{C}_{g_{u}}^{g_{u} /2} h u = 2 C g u g u / 2 种选法。
如果g u g_{u} g u 是偶数,为了使得0 0 0 和1 1 1 的数量之差为1 1 1 ,
如果u u u 选择1 1 1 ,则需要在u u u 的子节点v v v 中选择g u 2 − 1 \frac{g_{u}}{2}-1 2 g u − 1 个1 1 1 和g u 2 + 1 \frac{g_{u}}{2}+1 2 g u + 1 个0 0 0 ; 如果u u u 选择0 0 0 ,则需要选择g u 2 \frac{g_{u}}{2} 2 g u 个1 1 1 和g u 2 \frac{g_{u}}{2} 2 g u 个0 0 0 。 这种情况下,总共有h u = C g u g u / 2 + C g u g u / 2 − 1 h_{u}=\operatorname{C}_{g_{u}}^{g_{u} /2}+\operatorname{C}_{g_{u}}^{g_{u} /2-1} h u = C g u g u / 2 + C g u g u / 2 − 1 种选法。
因此有f u = h u ⋅ ∏ f v f_{u}=h_{u}\cdot\prod f_{v} f u = h u ⋅ ∏ f v ,f f f 数组可省略。
k = 1 k=1 k = 1 的答案是{ f 1 , 0 = f 1 , 2 ∣ n f 1 , 1 + f 1 , − 1 = 2 f 1 , 2 ∤ n \begin{cases}f_{1,0}=f_{1} ,& 2\mid n \\f_{1,1}+f_{1,-1}=2f_{1} ,& 2\nmid n\end{cases} { f 1 , 0 = f 1 , f 1 , 1 + f 1 , − 1 = 2 f 1 , 2 ∣ n 2 ∤ n 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int n, k;cin >> n >> k; vector<int > p (n + 1 ) ;for (int u = 2 ; u <= n; ++u) cin >> p[u];vector<int > g (n + 1 ) ;Z f = 1 ; for (int v = n; v; --v) { if (g[v] % 2 == 0 ) { f *= C (g[v], g[v] / 2 - 1 ) + C (g[v], g[v] / 2 ); g[p[v]]++; } else { f *= 2 * C (g[v], g[v] / 2 ); } } if (n % 2 == 1 ) f *= 2 ;cout << qpow (f, k) << '\n' ;
2024 杭电多校 8005 - cats 的二分答案1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 constexpr int D = 60 ;ll C[D + 1 ][D + 1 ]; void beforeT () { for (int i = 0 ; i <= D; ++i) { C[i][0 ] = C[i][i] = 1 ; for (int j = 1 ; j < i; ++j) C[i][j] = (C[i - 1 ][j - 1 ] + C[i - 1 ][j]); } } void eachT () { ll l = read (), r = read (); int k = min ((ll)D, read ()); ll n = r - l + 1 ; int m = __lg(n) + ((n & (n + 1 )) == 0 ); vector<ll> res (128 ) ; for (int i = 0 ; i < D; ++i) { res[i] += C[m][i + 1 ]; } n -= (1ll << m) - 1 ; int st = 0 ; for (int bit = D; ~bit; --bit) { if (n & (1ll << bit)) { for (int i = 0 ; i <= bit; ++i) { res[st + i] += C[bit][i]; } st += 1 ; } } ll ans = 0 ; for (int i = 0 ; i <= k; ++i) { ans += res[i]; } printf ("%lld\n" , ans); }
2024 杭电多校 1012 - 并[[…/contests/2024杭电多校/2024-07-19:2024“钉耙编程”中国大学生算法设计超级联赛(1)|2024-07-19:2024“钉耙编程”中国大学生算法设计超级联赛(1)]]
平面直角坐标系上有n n n 个矩形,其中第i i i 个的左上角坐标为( x i , 1 , y i , 1 ) (x_{i,1},y_{i,1}) ( x i , 1 , y i , 1 ) ,右下角坐标为( x i , 2 , y i , 2 ) (x_{i,2},y_{i,2}) ( x i , 2 , y i , 2 ) 。 对于k ∈ [ 1 , n ] k \in [1,n] k ∈ [ 1 , n ] ,求解在n n n 个矩形中随机选取k k k 个不同的矩形,其所有覆盖部分的并集的面积的期望值。
数据范围:n ⩽ 2 × 1 0 3 n \leqslant 2 \times 10^3 n ⩽ 2 × 1 0 3 。
暴力扫描每个位置有几个矩形覆盖,先离散化,记g i g_{i} g i 表示n n n 个矩形中有c c c 个矩形覆盖的面积和,k k k 的答案为
∑ i = 1 n ( 1 − C n − i k ) g i C n k \sum_{i=1}^{n} \dfrac{(1-\operatorname{C}_{n-i}^{k})g_{i}}{\operatorname{C}_{n}^{k}} i = 1 ∑ n C n k ( 1 − C n − i k ) g i
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 void eachT () { int n = read (); vector<int > allx, ally; allx.push_back (0 ); ally.push_back (0 ); vector<array<int , 4>> f (n); for (auto & [x1, y1, x2, y2] : f) { x1 = read (), y1 = read (), x2 = read (), y2 = read (); allx.push_back (x1); allx.push_back (x2); ally.push_back (y1); ally.push_back (y2); } sort (allx.begin (), allx.end ()); sort (ally.begin (), ally.end ()); allx.erase (unique (allx.begin (), allx.end ()), allx.end ()); ally.erase (unique (ally.begin (), ally.end ()), ally.end ()); int x = allx.size (), y = ally.size (); vector w (x, vector<int >(y)) ; for (auto & [x1, y1, x2, y2] : f) { x1 = lower_bound (allx.begin (), allx.end (), x1) - allx.begin (); y1 = lower_bound (ally.begin (), ally.end (), y1) - ally.begin (); x2 = lower_bound (allx.begin (), allx.end (), x2) - allx.begin (); y2 = lower_bound (ally.begin (), ally.end (), y2) - ally.begin (); ++w[x1][y1]; --w[x2][y1]; --w[x1][y2]; ++w[x2][y2]; } for (int i = 1 ; i < x; i++) { for (int j = 1 ; j < y; j++) { w[i][j] += w[i][j - 1 ]; } } vector<Z> g (n + 1 ) ; for (int i = 1 ; i < x - 1 ; i++) { for (int j = 1 ; j < y - 1 ; j++) { w[i][j] += w[i - 1 ][j]; g[w[i][j]] += 1ll * (allx[i + 1 ] - allx[i]) * (ally[j + 1 ] - ally[j]); } } Z sum = 0 ; for (int i = 1 ; i <= n; i++) { sum += g[i]; } for (int k = 1 ; k <= n; k++) { Z ans = 0 ; for (int i = 1 ; i <= n; i++) { ans -= C[n - i][k] * g[i]; } ans /= C[n][k]; ans += sum; cout << ans << endl; } }
2024 杭电多校 5013 - 飞行棋[[…/contests/2024杭电多校/2024-08-02:2024“钉耙编程”中国大学生算法设计超级联赛(5)#5013 - 飞行棋 (50)|2024-08-02:2024“钉耙编程”中国大学生算法设计超级联赛(5)]]
有n + 1 n + 1 n + 1 个的格子编号0 0 0 到n n n ,0 0 0 号格子为起点,n n n 号格子为终点。花费1 1 1 的代价等概率随机[ 1 , n ] [1,n] [ 1 , n ] 中的一个整数x x x ,向终点走x x x 步,若达到终点还有剩余步数则反向行走。如果随机到了数字n n n 并且未抵达终点则赠送一次(即不花费代价)等概率随机[ 1 , n − 1 ] [1,n - 1] [ 1 , n − 1 ] 中整数y y y 的机会,并向终点走y y y 步,若达到终点还有剩余步数则反向行走。求能恰好抵达终点的代价的期望,对1000000007 1000000007 1 0 0 0 0 0 0 0 0 7 取模。
方法一 设p i p_{i} p i 表示到达终点时代价为i i i 的概率,有
p i = { 1 n , i = 1 ( 1 − p 1 − p 2 − ⋯ − p i − 1 ) ( 1 n + 1 n ⋅ 1 n − 1 ) , i > 1 p_{i}= \begin{cases} \displaystyle\frac{1}{n}, & i=1 \\ \displaystyle(1-p_{1}-p_{2}-\dots-p_{i-1})\Big(\frac{1}{n}+\frac{1}{n}\cdot\frac{1}{n-1}\Big),& i>1 \end{cases} p i = ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧ n 1 , ( 1 − p 1 − p 2 − ⋯ − p i − 1 ) ( n 1 + n 1 ⋅ n − 1 1 ) , i = 1 i > 1
计算得
p i = { 1 n , i = 1 ( n − 2 ) i − 2 n ( n − 1 ) i − 2 , i > 1 p_{i}= \begin{cases} \displaystyle \frac{1}{n}, & i=1 \\ \dfrac{(n-2)^{i-2}}{n(n-1)^{i-2}}, &i>1 \end{cases} p i = ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧ n 1 , n ( n − 1 ) i − 2 ( n − 2 ) i − 2 , i = 1 i > 1
因此答案为
1 n + 1 n ∑ i = 2 ∞ i ⋅ ( n − 2 n − 1 ) i − 2 = n − 1 + 1 n \frac{1}{n}+\frac{1}{n}\sum_{i=2}^{\infty}i\cdot\Big(\dfrac{n-2}{n-1}\Big)^{i-2}=n-1+\dfrac{1}{n} n 1 + n 1 i = 2 ∑ ∞ i ⋅ ( n − 1 n − 2 ) i − 2 = n − 1 + n 1
方法二 在0 0 0 号格时有1 n \cfrac{1}{n} n 1 的概率直接进入终点。对另外n − 1 n \cfrac{n-1}{n} n n − 1 概率发生的情况,从1 1 1 号格到n − 1 n-1 n − 1 号格花费1 1 1 的代价进入终点的期望是相同的,都是1 n − 1 \cfrac{1}{n-1} n − 1 1 ,另外n − 2 n − 1 \cfrac{n-2}{n-1} n − 1 n − 2 的概率继续停留在1 ∼ n − 1 1 \sim n-1 1 ∼ n − 1 号格内,故在这个问题上,位于1 ∼ n − 1 1 \sim n-1 1 ∼ n − 1 号格子上的状态都是等价的。所以期望花费的代价为
1 + n − 1 n ⋅ ( n − 1 ) = n − 1 + 1 n 1+\cfrac{n-1}{n} \cdot(n-1)=n-1+\dfrac{1}{n} 1 + n n − 1 ⋅ ( n − 1 ) = n − 1 + n 1
2024 牛客多校 4J - Zero[[…/contests/2024牛客多校/2024-07-25:2024牛客暑期多校训练营4#*J - Zero|2024-07-25:2024牛客暑期多校训练营4]]
给出一个 01 带? ? ? 的串,? ? ? 等概率变成0 0 0 或1 1 1 。一段连续相同数的贡献是区间和的p p p 次幂。问期望贡献和。
设f i , j f_{i,j} f i , j 表示以第i i i 位为区间右端点,p = j p=j p = j 的期望贡献和。因x 0 = 1 x^{0}=1 x 0 = 1 ,故初始f ∗ , 0 = 1 f_{*,0}=1 f ∗ , 0 = 1 ,注意到( x + 1 ) j = ∑ C j k x k (x+1)^{j}=\sum\operatorname{C}_{j}^{k}x^{k} ( x + 1 ) j = ∑ C j k x k ,有转移方程
f i , j ← { 0 , s i = 0 ∑ k = 0 j C j k f i − 1 , k , s i = 1 1 2 ∑ k = 0 j C j k f i − 1 , k , s i = ? f_{i,j} \leftarrow \begin{cases} 0,&s_{i}=0 \\ \displaystyle\sum_{k=0}^{j} \operatorname{C}_{j}^{k}f_{i-1,k} ,&s_{i}=1 \\ \displaystyle \cfrac{1}{2}\sum_{k=0}^{j} \operatorname{C}_{j}^{k}f_{i-1,k},&s_{i}=? \end{cases} f i , j ← ⎩ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎧ 0 , k = 0 ∑ j C j k f i − 1 , k , 2 1 k = 0 ∑ j C j k f i − 1 , k , s i = 0 s i = 1 s i = ?
答案为∑ f ∗ , k \sum f_{*,k} ∑ f ∗ , k 。时间复杂度Θ ( n k 2 ) \Theta(nk^{2}) Θ ( n k 2 ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 using Z = ModInt<998244353 >;Z f[N][M]; void eachT () { int n, p; string s; cin >> n >> p >> s; s = ' ' + s; Z ans = 0 ; f[0 ][0 ] = 1 ; for (int i = 1 ; i <= n; i++) { for (int j = 0 ; j <= p; j++) { for (int k = 0 ; k <= j; k++) { f[i][j] += C[j][k] * f[i - 1 ][k]; } if (s[i] == '0' ) f[i][j] = 0 ; if (s[i] == '?' ) f[i][j] *= inv2; } f[i][0 ] += 1 ; ans += f[i][p]; } cout << ans << "\n" ; }
2024 牛客多校 1A - A Bit Common[[…/contests/2024牛客多校/2024-07-16:2024牛客暑期多校训练营1#A - A Bit Common|2024-07-16:2024牛客暑期多校训练营1]]
题意 求有多少长为n n n 的元素是[ 0 , 2 m ) [0, 2^m) [ 0 , 2 m ) 的整数序列,满足存在一个非空子序列的 AND 和都是 1,答案对输入的正整数q q q 取模.
思路 二进制最低位为 0 的数一定不在 AND 和是 1 的子序列里,这些数除了最低位都可以任选.
对于二进制最低位为 1 的数,如果存在一个子序列的 AND 和是 1,那么包含这个子序列的子序列的 AND 和也是 1,只要所有二进制最低位为 1 的数 AND 和是 1 就能满足条件.
记二进制最低位为 1 的数有k > 0 k > 0 k > 0 个,这些数除了最低位的 AND 和都要是 0,也就是每一位上这些数都至少有一个是1 1 1 .
总方案:
∑ k = 1 n C n k 2 ( n − k ) ( m − 1 ) ( 2 k − 1 ) m − 1 \sum_{k=1}^{n}\operatorname{C}_{n}^{k}2^{(n-k)(m-1)}(2^{k}-1)^{m-1} k = 1 ∑ n C n k 2 ( n − k ) ( m − 1 ) ( 2 k − 1 ) m − 1
2024 牛客多校 1B - A Bit More Common[[…/contests/2024牛客多校/2024-07-16:2024牛客暑期多校训练营1#*B - A Bit More Common|2024-07-16:2024牛客暑期多校训练营1]]
题意 求有多少长为n n n 的元素是[ 0 , 2 m ) [0, 2^m) [ 0 , 2 m ) 的整数序列,满足存在两个不同的非空子序列的 AND 和是1 1 1 ,答案对输入的正整数q q q 取模.
思路 也就是说,从刚才找到的子序列中移除某个,剩下的子序列的 AND 和仍是1 1 1 .
考虑反面,移除任意一个,剩下的子序列的 AND 和都不是1 1 1 .因此,每个数应当包含至少一个 独一无二的 0 (自己的这一位是 0,其它数的这一位都是 1).
——止步于此——
难以直接计算,故递推.
设f i , j f_{i,j} f i , j 表示i i i 个数,共有j j j 个独一无二的 0 的方案数(显然,每一个独一无二的 0 只能属于一个数).递推方程:
f i , j = { 1 i = 1 i ⋅ ( f i , j − 1 + f i − 1 , j − 1 ) 1 < i ⩽ j 0 i > j f_{i,j}= \begin{cases} 1 & i=1 \\ i\cdot(f_{i,j-1}+f_{i-1,j-1}) & 1<i \leqslant j \\ 0&i>j \end{cases} f i , j = ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧ 1 i ⋅ ( f i , j − 1 + f i − 1 , j − 1 ) 0 i = 1 1 < i ⩽ j i > j
反面的总方案:
∑ k = 2 n C n k 2 ( n − k ) ( m − 1 ) ∑ j = k m − 1 C m − 1 j ( 2 k − k − 1 ) m − 1 − j \sum_{k=2}^{n}\operatorname{C}_{n}^{k}2^{(n-k)(m-1)} \sum_{j=k}^{m-1}\operatorname{C}_{m-1}^{j}(2^{k}-k-1)^{m-1-j} k = 2 ∑ n C n k 2 ( n − k ) ( m − 1 ) j = k ∑ m − 1 C m − 1 j ( 2 k − k − 1 ) m − 1 − j
注意k = 1 k=1 k = 1 是个特例,此时一定无解.
因此总方案:
∑ k = 2 n C n k 2 ( n − k ) ( m − 1 ) [ ( 2 k − 1 ) m − 1 − ∑ j = k m − 1 C m − 1 j f k , j ⋅ ( 2 k − k − 1 ) m − 1 − j ] \sum_{k=2}^{n}\operatorname{C}_{n}^{k}2^{(n-k)(m-1)} \left[ (2^{k}-1)^{m-1}-\sum_{j=k}^{m-1}\operatorname{C}_{m-1}^{j}f_{k,j}\cdot(2^{k}-k-1)^{m-1-j} \right] k = 2 ∑ n C n k 2 ( n − k ) ( m − 1 ) ⎣ ⎢ ⎡ ( 2 k − 1 ) m − 1 − j = k ∑ m − 1 C m − 1 j f k , j ⋅ ( 2 k − k − 1 ) m − 1 − j ⎦ ⎥ ⎤
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ll ans = 0 ; for (int k = 2 ; k <= n; ++k) { ll res = 0 ; for (int j = k; j <= m - 1 ; ++j) { res += C[m - 1 ][j] * f[k][j] % MOD * qpow (qpow (2 , k, MOD) - k - 1 + MOD, m - 1 - j, MOD) % MOD; res %= MOD; } res = qpow (qpow (2 , k, MOD) - 1 , m - 1 , MOD) % MOD - res; res = (res % MOD + MOD) % MOD; ans += C[n][k] * qpow (2 , (m - 1 ) * (n - k), MOD) % MOD * res % MOD; ans %= MOD; } printf ("%lld\n" , ans);
时间复杂度已经达到Θ ( m n log 2 N ) \Theta(mn\log^{2} N) Θ ( m n log 2 N ) ,应当优化快速幂.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <cstdio> using ll = long long ;inline ll read () { ll S = 0 , C = 0 ; char Y = getchar (); while (Y > 57 || Y < 48 ) C |= Y == 45 , Y = getchar (); while (Y <= 57 && Y >= 48 ) S = (S << 3 ) + (S << 1 ) + Y - 48 , Y = getchar (); return C ? -S : S; } inline ll qpow (ll S, ll Y, ll MOD) { ll C = 1 ; while (Y) { if (Y & 1 ) C = C * S % MOD; S = S * S % MOD; Y >>= 1 ; } return C; } const int N = 5000 + 8 ;ll C[N][N], f[N][N]; ll pow2[N]; int main () { ll n = read (), m = read (), MOD = read (); for (int i = 0 ; i < N; ++i) { C[i][0 ] = 1 ; C[i][i] = 1 ; for (int j = 1 ; j < i; ++j) C[i][j] = (C[i - 1 ][j - 1 ] + C[i - 1 ][j]) % MOD; } for (int j = 1 ; j <= m - 1 ; ++j) { f[1 ][j] = 1 ; } for (int i = 2 ; i <= n; ++i) { for (int j = i; j <= m - 1 ; ++j) { f[i][j] = i * (f[i][j - 1 ] + f[i - 1 ][j - 1 ]) % MOD; } } ll ans = 0 ; pow2[1 ] = 2 ; for (int k = 2 ; k <= n; ++k) { pow2[k] = pow2[k - 1 ] * 2 % MOD; ll res = 0 ; for (int j = k; j <= m - 1 ; ++j) { res += C[m - 1 ][j] * f[k][j] % MOD * qpow (pow2[k] - k - 1 + MOD, m - 1 - j, MOD) % MOD; res %= MOD; } res = qpow (pow2[k] - 1 , m - 1 , MOD) % MOD - res; res = (res % MOD + MOD) % MOD; ans += C[n][k] * qpow (2 , (m - 1 ) * (n - k), MOD) % MOD * res % MOD; ans %= MOD; } printf ("%lld\n" , ans); return 0 ; }
题意 给出三根木棍的长度a , b , c a,~b,~c a , b , c ,可以给这三根木棍增加一些长度,长度是非负整数且总和不超过L L L ,求增加后这三根木棍可构成的非退化三角形的方法数。
换言之,确定数对( Δ a , Δ b , Δ c ) (\Delta{a},~\Delta{b},~\Delta{c}) ( Δ a , Δ b , Δ c ) 的组数,使得下式成立:
{ a + Δ a < b + Δ b + c + Δ c b + Δ b < a + Δ a + c + Δ c c + Δ c < a + Δ a + b + Δ b Δ a + Δ b + Δ c ⩽ l \begin{cases} a+\Delta{a}<b+\Delta{b}+c+\Delta{c}\\ b+\Delta{b}<a+\Delta{a}+c+\Delta{c}\\ c+\Delta{c}<a+\Delta{a}+b+\Delta{b}\\ \Delta{a}+\Delta{b}+\Delta{c} \leqslant l \end{cases} ⎩ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎧ a + Δ a < b + Δ b + c + Δ c b + Δ b < a + Δ a + c + Δ c c + Δ c < a + Δ a + b + Δ b Δ a + Δ b + Δ c ⩽ l
输入只有四个数,输出只有一个数,这道题一定非!常!简!单! 而且是A题哦~~~(不告诉你是Div1的)~~
思路一 既然是数学题那当然要用数学的方法了:从反面考虑,所求方法数是总方法数减去不合法的方法数。
引理一 将m m m 个相同的球放到n n n 个不同的盒子(允许空)中的方法数为C m + n − 1 n − 1 C_{m+n-1}^{n-1} C m + n − 1 n − 1 。利用插板法,这是熟知的结论。
引理二 ∑ k = 0 n C k + m m = C n + m + 1 m + 1 \sum\limits_{k=0}^{n}C_{k+m}^{m}=C_{n+m+1}^{m+1} k = 0 ∑ n C k + m m = C n + m + 1 m + 1 。
下文会频繁用到这两个结果,请留意。
S t e p 1 \mathbb{Step1}\quad S t e p 1 总方法数为∑ k = 0 L C k + 2 2 = C L + 3 3 \sum\limits_{k=0}^{L}C_{k+2}^{2}=C_{L+3}^{3} k = 0 ∑ L C k + 2 2 = C L + 3 3 ,表示枚举将k ∈ [ 0 , L ] ∩ Z k\in\left[0,L\right]\cap\mathbb{Z} k ∈ [ 0 , L ] ∩ Z 个棍子分给三个盒子a , b , c a,b,c a , b , c 。事实上,它与将L L L 个棍子分给四个盒子等价,这四个盒子分别是a , b , c a,b,c a , b , c 和未使用。
S t e p 2 \mathbb{Step2}\quad S t e p 2 不合法即是一边大于等于另两边之和。
若操作后a a a 为最长边,即a ′ ⩾ b ′ + c ′ a'\geqslant b'+c' a ′ ⩾ b ′ + c ′ 。
此时枚举分给a a a 的棍子i = Δ a i=\Delta a i = Δ a 的上界依旧是i ⩽ L i\leqslant L i ⩽ L ,但下界需要更改为i ⩾ b + c − a i\geqslant b+c-a i ⩾ b + c − a (这是由于a + Δ a = a ′ ⩾ b ′ + c ′ ⩾ b + c a+\Delta a=a'\geqslant b'+c'\geqslant b+c a + Δ a = a ′ ⩾ b ′ + c ′ ⩾ b + c ),当然,下界不能为负数,故确切的下界为i ⩾ max ( 0 , b + c − a ) i\geqslant \max{(0,~b+c-a)} i ⩾ max ( 0 , b + c − a ) 。
剩下j = L − i j=L-i j = L − i 个棍子分给b b b 和c c c ,即j = Δ b + Δ c j=\Delta b+\Delta c j = Δ b + Δ c 。首先注意,棍子数j j j 不能超过a + i − b − c a+i-b-c a + i − b − c ,这是由于a + i = a ′ ⩾ b ′ + c ′ = b + c + Δ b + Δ c = b + c + j a+i=a'\geqslant b'+c'=b+c+\Delta b+\Delta c=b+c+j a + i = a ′ ⩾ b ′ + c ′ = b + c + Δ b + Δ c = b + c + j 。因此,0 ⩽ j ⩽ min ( L − i , a + i − b − c ) ) 0\leqslant j\leqslant\min{\big(L-i,~a+i-b-c)\big)} 0 ⩽ j ⩽ min ( L − i , a + i − b − c ) ) 。由引理,对每个确定的i i i ,方法数为
∑ j = 0 min ( L − i , a + i − b − c ) ) C j + 1 1 = C min ( L − i , a + i − b − c ) ) + 2 2 \sum\limits_{j=0}^{\min{\big(L-i,~a+i-b-c)\big)}}C_{j+1}^{1}=C_{\min{\big(L-i,~a+i-b-c)\big)}+2}^{2} j = 0 ∑ m i n ( L − i , a + i − b − c ) ) C j + 1 1 = C m i n ( L − i , a + i − b − c ) ) + 2 2
对i , j i,~j i , j 求和即得此时的方法数为
∑ i = max ( 0 , b + c − a ) L C min ( L − i , a + i − b − c ) ) + 2 2 = ? \sum\limits_{i=\max{(0,~b+c-a)}}^{L}C_{\min{\big(L-i,~a+i-b-c)\big)}+2}^{2}=? i = m a x ( 0 , b + c − a ) ∑ L C m i n ( L − i , a + i − b − c ) ) + 2 2 = ?
S t e p 3 \mathbb{Step3}\quad S t e p 3 这个结果太丑了,我们希望使用数学知识加以化简,尤其是去掉∑ \sum ∑ 。先看右边的m i n \rm min m i n ,它是关于i i i 的两个一次函数的最小值,图像应当是一条折线。那么结果即是
\begin{align} S=C_{L+3}^{3} &-\sum\limits_{k=\max{(0,~b+c-a)}}^{L}C_{\min{\big(L-k,~k-(b+c-a)\big)}+2}^{2} \\ &-\sum\limits_{k=\max{(0,~c+a-b)}}^{L}C_{\min{\big(L-k,~k-(c+a-b)\big)}+2}^{2} \\ &-\sum\limits_{k=\max{(0,~a+b-c)}}^{L}C_{\min{\big(L-k,~k-(a+b-c)\big)}+2}^{2} \\ \end{align}
思路二 依旧是数学方法,但是从正面考虑
设a , b , c a,~b,~c a , b , c 的增量分别为Δ a , Δ b , Δ c \Delta{a},~\Delta{b},~\Delta{c} Δ a , Δ b , Δ c ,并令m = c − a − b , n = b − a − c , p = a − b − c m=c-a-b,n=b-a-c,p=a-b-c m = c − a − b , n = b − a − c , p = a − b − c ,则
{ a + Δ a < b + Δ b + c + Δ c b + Δ b < a + Δ a + c + Δ c c + Δ c < a + Δ a + b + Δ b Δ a + Δ b + Δ c ⩽ l ⟺ { Δ a + Δ b − Δ c > m Δ a + Δ c − Δ b > n Δ b + Δ c − Δ a > p Δ a + Δ b + Δ c ⩽ l \begin{cases} a+\Delta{a}<b+\Delta{b}+c+\Delta{c}\\ b+\Delta{b}<a+\Delta{a}+c+\Delta{c}\\ c+\Delta{c}<a+\Delta{a}+b+\Delta{b}\\ \Delta{a}+\Delta{b}+\Delta{c} \leqslant l \end{cases} \iff \begin{cases} \Delta{a}+\Delta{b}-\Delta{c}>m\\ \Delta{a}+\Delta{c}-\Delta{b}>n\\ \Delta{b}+\Delta{c}-\Delta{a}>p\\ \Delta{a}+\Delta{b}+\Delta{c} \leqslant l \end{cases} ⎩ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎧ a + Δ a < b + Δ b + c + Δ c b + Δ b < a + Δ a + c + Δ c c + Δ c < a + Δ a + b + Δ b Δ a + Δ b + Δ c ⩽ l ⟺ ⎩ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎧ Δ a + Δ b − Δ c > m Δ a + Δ c − Δ b > n Δ b + Δ c − Δ a > p Δ a + Δ b + Δ c ⩽ l
令w = Δ a − Δ b , s = Δ a + Δ b w=\Delta{a}-\Delta{b},s=\Delta{a}+\Delta{b} w = Δ a − Δ b , s = Δ a + Δ b ,且w , s w,s w , s 的奇偶性一致。
我们枚举w w w ,计算在每个w w w 下有多少种方法。
那么有Δ c > max ( n − w , p + w ) \Delta{c}>\max(n-w,p+w) Δ c > max ( n − w , p + w )
因为Δ a , Δ b ⩾ 0 \Delta{a},\Delta{b}\geqslant0 Δ a , Δ b ⩾ 0 ,所以∣ w ∣ ⩽ s ⩽ l − Δ c |w|\leqslant s\leqslant l-\Delta{c} ∣ w ∣ ⩽ s ⩽ l − Δ c
接下来考虑把答案分成两部分来计算
第一部分是s ⩾ ⌈ l + m + 1 2 ⌉ s\geqslant\lceil \frac{l+m+1}{2}\rceil s ⩾ ⌈ 2 l + m + 1 ⌉ ,这个时候Δ a + Δ b + Δ c ⩽ l \Delta{a}+\Delta{b}+\Delta{c}\leqslant l Δ a + Δ b + Δ c ⩽ l 的限制比Δ a + Δ b − Δ c ⩾ m + 1 \Delta{a}+\Delta{b}-\Delta{c}\geqslant m+1 Δ a + Δ b − Δ c ⩾ m + 1 的限制更紧
因为Δ a = s + w 2 , Δ b = s − w 2 \Delta{a}=\frac{s+w}{2},\Delta{b}=\frac{s-w}{2} Δ a = 2 s + w , Δ b = 2 s − w ,所以
那么就是一个等差数列求和的形式了,首项与公差为1 1 1 ,项数就是l − max ( n − w , p + w ) − max ( ⌈ l + m + 1 2 ⌉ , ∣ w ∣ ) ) 2 \frac{l-\max(n-w,p+w)-\max(\lceil \frac{l+m+1}{2}\rceil,|w|))}{2} 2 l − m a x ( n − w , p + w ) − m a x ( ⌈ 2 l + m + 1 ⌉ , ∣ w ∣ ) ) 但由于奇偶需要一致,所以需要微调一下,详见代码
第二部分是s ⩽ s\leqslant s ⩽ 刚才那个值,这个时候Δ a + Δ b − Δ c ⩾ m + 1 \Delta{a}+\Delta{b}-\Delta{c}\geqslant m+1 Δ a + Δ b − Δ c ⩾ m + 1 的限制更紧,求答案总数的方法同上。
2024 杭电多校 1005 - 博弈[[…/contests/2024杭电多校/2024-07-19:2024“钉耙编程”中国大学生算法设计超级联赛(1)|2024-07-19:2024“钉耙编程”中国大学生算法设计超级联赛(1)]]
题意 给定一个可重小写字符集合S S S . Alice 初始时有空串A A A ,Bob 初始时有空串B B B . 两人轮流等概率取出集合S S S 中的一个字符c c c ,将它拼接到自己的字符串的后面,直至S S S 为空,每个字符只能被取一次,Alice 先手.如果最终A A A 的字典序严格大于B B B ,则 Alice 胜.求 Alice 胜的概率,答案对998244353 998244353 9 9 8 2 4 4 3 5 3 取模.
思路 如果在某个字符i i i ,A i > B i A_{i}>B_{i} A i > B i ,则已有 Alice 胜;若A i < B i A_{i}<B_{i} A i < B i ,则 Alice 败;否则A i = B i A_{i}=B_{i} A i = B i ,这个字符无法判断胜负,需要继续操作,我们称这种情形为 平局 .非平局时,两人互换结果,输赢翻转,概率相同,因此只需判断平局的概率.分为以下三种情形,式中p = ∏ A 字符 i 的总数 字符 i 的组数 × 组数 ! 总数 ! p=\frac{\prod \operatorname{A}_{\text{字符}i\text{的总数}}^{\text{字符}i\text{的组数}}\times\text{组数}!}{\text{总数}!} p = 总数 ! ∏ A 字符 i 的总数 字符 i 的组数 × 组数 ! :
若每种字母的个数都是偶数:设 Alice 和 Bob 取得的字符串完全相同的概率为p p p ,则答案为1 − p 2 \frac{1-p}{2} 2 1 − p . 若只有一种字母的个数是奇数:对于前n − 1 2 \frac{n-1}{2} 2 n − 1 个字符,设 Alice 和 Bob 取得的字符串完全相同的概率为p p p ,则答案为1 − p 2 + p = 1 + p 2 \frac{1-p}{2}+p=\frac{1+p}{2} 2 1 − p + p = 2 1 + p . 否则,答案为1 2 \frac{1}{2} 2 1 . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void eachT () { int n = read (); int cnt[2 ] = { 0 ,0 }; for (int i = 1 ; i <= n; i++) { char x; scanf ("%c" , &x); a[i] = read (); cnt[a[i] & 1 ] += 1 ; } if (cnt[1 ] > 1 ) { printf ("%lld\n" , inv2); return ; } ll ans = 1 , ttcnt = 0 ; for (int i = 1 ; i <= n; i++) { ans = ans * fac[a[i]] % MOD * facinv[a[i] / 2 ] % MOD; ttcnt += a[i]; } ans = ans * facinv[ttcnt] % MOD * fac[ttcnt/2 ] % MOD; if (cnt[1 ] == 0 ) printf ("%lld\n" , (1 - ans + MOD) % MOD * inv2 % MOD); else printf ("%lld\n" , (1 + ans + MOD) % MOD * inv2 % MOD); }
题意 n n n 个人,m m m 对朋友,第j j j 对朋友的友谊值为f j ( 1 ⩽ j ⩽ m ) f_j~(1\leqslant j\leqslant m) f j ( 1 ⩽ j ⩽ m ) ,进行k k k 次选择,每次等概率地选择俩人,如果选择的俩人是一对朋友,他们的友谊值将增加1 1 1 .求所有被选中的k k k 对的友谊值总和的期望值(在增加之前).
思路 易知分母是( C n 2 ) k (C_n^2)^k ( C n 2 ) k ,它表示每次选择有C n 2 C_n^2 C n 2 种选择方式,共选择k k k 次,以下计算分子,分子是所有可能的选择方式的友谊值的总和.
因为只考虑友谊值的总和,它符合加法原理,所以可以按照朋友分开计算友谊值,再相加.
对于某对朋友,可能选择了0 ∼ k 0\sim k 0 ∼ k 次,如在k k k 次选择中选择i i i 次这对朋友,根据二项式定理,有C k i ⋅ 1 i ⋅ ( C n 2 − 1 ) k − i C_k^i\cdot 1^i\cdot\big(C_n^2-1\big)^{k-i} C k i ⋅ 1 i ⋅ ( C n 2 − 1 ) k − i 种选择方式,每种选择的友谊值总和为f + ( f + 1 ) + ( f + 2 ) + ⋯ + ( f + i − 1 ) = i f + C i 2 f+(f+1)+(f+2)+\dots+(f+i-1)=if+C_i^2 f + ( f + 1 ) + ( f + 2 ) + ⋯ + ( f + i − 1 ) = i f + C i 2 ,因此所有情况的友谊值的总和为C k i p k − i ( i f + C i 2 ) C_k^ip^{k-i}\big(if+C_i^2\big) C k i p k − i ( i f + C i 2 ) .(为了书写方便,这里记p = C n 2 p=C_n^2 p = C n 2 ,下同)
将上式对i i i 求和,稍加化简,即
\begin{align} S_j &=\sum_{i=0}^{k} C_k^i (p-1)^{k-i} \big(if+C_i^2\big) \\ &= \sum_{i=1}^{k} i C_k^i (p-1)^{k-i}f + \frac12\sum_{i=2}^{k} i(i-1) C_k^i (p-1)^{k-i} \\ &= \sum_{i=1}^{k} kC_{k-1}^{i-1} (p-1)^{k-i}f + \frac12\sum_{i=2}^{k} k(k-1)C_{k-2}^{i-2} (p-1)^{k-i} \\ &= kf\sum_{i=0}^{k-1} C_{k-1}^{i} (p-1)^{k-1-i} + \frac12k(k-1)\sum_{i=0}^{k-2} C_{k-2}^{i} (p-1)^{k-2-i} \\ &= kfp^{k-1} + \frac12k(k-1)p^{k-2}, \\ \end{align}
熟知,∑ i = 0 k C k i p k − i = ( p + 1 ) k \sum\limits_{i=0}^{k} C_{k}^{i} p^{k-i} = (p+1)^{k} i = 0 ∑ k C k i p k − i = ( p + 1 ) k .
由于有m m m 对朋友,对这些朋友求和,
\begin{align} \sum_{j=1}^{m}S_j &=\sum_{j=1}^{m} \Big(kf_jp^{k-1} + \frac12k(k-1)p^{k-2} \Big) \\ &=kp^{k-1}\sum_{j=1}^{m}f_j + mC_k^2p^{k-2}, \\ \end{align}
即是最终的分子.
答案即是
a n s = k p k − 1 ∑ j = 1 m f j + m C k 2 p k − 2 ( C n 2 ) k . {\rm ans} = \frac{kp^{k-1}\sum_{j=1}^{m}f_j + mC_k^2p^{k-2}}{(C_n^2)^k}. a n s = ( C n 2 ) k k p k − 1 ∑ j = 1 m f j + m C k 2 p k − 2 .
核心部分:
1 2 3 4 5 6 7 8 ll n = read (), m = read (), k = read (); ll p = C2 (n), ans = C2 (k) * m * qpow (p, k - 2 ), sum = 0 ; while (m--) { read (), read (); sum += read (); } ans += k * sum * qpow (p, k - 1 ); print (ans * qpow (qpow (p, k), MOD - 2 ));
时间复杂度Θ ( m + log n ) \Theta(m+\log n) Θ ( m + log n ) ,77ms.
评注 数据范围较小,不化简也能过.
题意 四种元素,按照1 → 2 , 3 , 2 → 1 , 4 , 3 → 2 , 3 , 4 → 1 , 4 1\to2,3,~2\to1,4,~3\to2,3,~4\to1,4 1 → 2 , 3 , 2 → 1 , 4 , 3 → 2 , 3 , 4 → 1 , 4 的顺序连接,求方法数。
思路 1 1 1 和2 2 2 必须交替排列,在中间插入若干3 3 3 ,4 4 4 。注意到,将n n n 个物品放入m m m 个盒子,不能留空的方法数为C n − 1 m − 1 C_{n-1}^{m-1} C n − 1 m − 1 ,允许不放的方法数为C n + m − 1 m − 1 C_{n+m-1}^{m-1} C n + m − 1 m − 1 。
1 2 3 4 5 6 7 int a = read (), b = read (), c = read (), d = read ();ll ans = 0 ; if (a == 0 && b == 0 ) ans = (c == 0 ) ^ (d == 0 ) || (c == 0 ) && (d == 0 );else if (a == b) ans = C (a - 1 + c, c, p) * C (b + d, d, p) + C (a + c, c, p) * C (b - 1 + d, d, p);else if (a == b + 1 ) ans = C (a - 1 + c, c, p) * C (b + d, d, p);else if (b == a + 1 ) ans = C (a + c, c, p) * C (b - 1 + d, d, p);printf ("%lld\n" , ans % p);
题意 给出一些木棍,它们的长度是2 a i 2^{a_i} 2 a i ,问选择三根能构成三角形的方法数.
思路 注意到∀ i < j < k , 2 i + 2 j < 2 k \forall i<j<k,~2^i+2^j<2^k ∀ i < j < k , 2 i + 2 j < 2 k ,它们不能构成三角形,因此可能的情况只有等边三角形(C3(mp[i])
)和腰比底长的等腰三角形(s[i-1] * C2(mp[i])
).
1 2 3 4 5 6 7 8 9 memset (mp, 0 , sizeof mp);int n = read ();ll ans = 0 , s = 0 ; for (int i = 1 ; i <= n; ++i) ++mp[read ()];for (int i = 0 ; i <= n; ++i) { ans += s * C2 (mp[i]) + C3 (mp[i]); s += mp[i]; } printf ("%lld\n" , ans);
2022 ICPC 杭州 A. Modulo Ruins the Legend题意 给定a , b , s , m a,b,s,m a , b , s , m ,最小化( x a + y b + s ) m o d m (xa+yb+s) \bmod m ( x a + y b + s ) m o d m 。([[…/contests/2024-09-25:The 2022 ICPC Asia Hangzhou Regional Contest|2024-09-25:The 2022 ICPC Asia Hangzhou Regional Contest]])
思路 根据裴蜀定理知存在x 0 , y 0 x_{0},y_{0} x 0 , y 0 ,使得x 0 a + y 0 b = d = ( a , b ) x_{0}a+y_{0}b=d=(a,b) x 0 a + y 0 b = d = ( a , b ) ,问题化为最小化( u d + s ) m o d m (ud+s) \bmod m ( u d + s ) m o d m ,其中u d = x a + y b , x = u x 0 , y = v y 0 ud=xa+yb,\ x=ux_{0},\ y=vy_{0} u d = x a + y b , x = u x 0 , y = v y 0 。
设答案为w ∈ [ 0 , m ) w\in[0,m) w ∈ [ 0 , m ) ,则u d + s + v m = w ud+s+vm=w u d + s + v m = w ,即u d + v m = w − s ud+vm=w-s u d + v m = w − s ,于是只能g = ( m , d ) ∣ w − s g=(m,d)\mid w-s g = ( m , d ) ∣ w − s ,因此取w = s m o d g w=s \bmod g w = s m o d g 。
解不定方程u d + v m = w − s ud+vm=w-s u d + v m = w − s 得到u , v u,v u , v ,再解不定方程u d = x a + y b ud=xa+yb u d = x a + y b 得到x , y x,y x , y 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int n, m;cin >> n >> m; ll sum = 0 ; for (int i = 0 ; i < n; i++) { int x; cin >> x; sum += x; } sum %= m; ll a = n, b = n * (n + 1 ) / 2 ; ll d = gcd (a, b), g = gcd (d, m); ll ans = sum % g; auto [k, t] = exexgcd (d, m, ans - sum);auto [x, y] = exexgcd (a, b, d * k);cout << ans << endl; cout << (x % m + m) % m << " " << (y % m + m) % m << endl;