文章目录
- description
- solution
- code
description
有TTT组测试数据
对于两个长度为KKK的数列{a}\{a\}{a}和{b}\{b\}{b},满足∑i=1Kai=N,∑i=1Kbi=M\sum_{i=1}^Ka_i=N,\sum_{i=1}^Kb_i=M∑i=1Kai=N,∑i=1Kbi=M
对于这两个数列,定义权值为P=∏i=1Kmin(ai,bi)P=\prod_{i=1}^K\min(a_i,b_i)P=∏i=1Kmin(ai,bi)
求所有可能的数列的权值之和∑{a},{b}P\sum_{\{a\},\{b\}}P∑{a},{b}P
答案对998244353998244353998244353取模
K≤min(N,M)N,M≤5e5T≤100K\le \min(N,M)\quad N,M\le 5e5\quad T\le 100K≤min(N,M)N,M≤5e5T≤100
solution
虽然代码非常短,但是要理解简直要命
我们可以构造一个二维数组c[2][K]c[2][K]c[2][K],要求c[0][i]=c[1][i]c[0][i]=c[1][i]c[0][i]=c[1][i],第i位不能为0
设计的初衷是让c[0][K]c[0][K]c[0][K]为构造{a}\{a\}{a},c[1][K]c[1][K]c[1][K]为构造{b}\{b\}{b}服务
再构造两个一维数组A[K],B[K]A[K],B[K]A[K],B[K],第i位可以为0
通过构造出来的这些数组生成最后的{a},{b}\{a\},\{b\}{a},{b}
- a[i]=c[0][i]+A[i]a[i]=c[0][i]+A[i]a[i]=c[0][i]+A[i]
- b[i]=c[1][i]+B[i]b[i]=c[1][i]+B[i]b[i]=c[1][i]+B[i]
定义∑i=1Kc[0][i]=∑i=1Kc[1][i]=S\sum_{i=1}^Kc[0][i]=\sum_{i=1}^Kc[1][i]=S∑i=1Kc[0][i]=∑i=1Kc[1][i]=S
则对于{a}\{a\}{a}序列而言,剩下的N−SN-SN−S就需要由AAA数组来弥补;{b}\{b\}{b}同理
考虑有多少个A/BA/BA/B数组满足其求和恰好弥补了空缺N−S/M−SN-S/M-SN−S/M−S
显然这可以通过组合数算出
- A:C(N−S+K−1,K−1)A:C(N-S+K-1,K-1)A:C(N−S+K−1,K−1)
- B:C(M−S+K−1,K−1)B:C(M-S+K-1,K-1)B:C(M−S+K−1,K−1)
以AAA数组的计算方式为例,BBB同理
相当于把剩下的N−SN-SN−S分成恰好KKK个盒子,隔板法,插入K−1K-1K−1个板子
但是AAA的条件可以为000,意味着盒子可以为空,但这是隔板法不能求得的
可以通过给每个盒子分配111的占位相当于一个盒子,等价于将限制变成至少为111
考虑C(N−S+K−1,K−1)∗C(M−S+K−1,K−1)C(N-S+K-1,K-1)*C(M-S+K-1,K-1)C(N−S+K−1,K−1)∗C(M−S+K−1,K−1)
发现这两个组合数相乘有非常实际的意义
这求出的恰好是将所有满足∀1≤i≤Kc[0][i]≤a[i]\forall_{1\le i\le K}\ c[0][i]\le a[i]∀1≤i≤K c[0][i]≤a[i]的{a}\{a\}{a}和∀1≤i≤Kc[0][i]≤b[i]{b}\forall_{1\le i\le K}\ c[0][i]\le b[i]\{b\}∀1≤i≤K c[0][i]≤b[i]{b}的组合都计算了恰好一次
接着我们考虑对于一组特定的ccc数组和特定的A,BA,BA,B数组(也就是一组特定的{a},{b}\{a\},\{b\}{a},{b})的贡献
∏i=1Kmin(ai,bi)\prod_{i=1}^K\min(a_i,b_i)∏i=1Kmin(ai,bi) 这是题目定义的贡献
思考一下,这样一组特定的{a},{b}\{a\},\{b\}{a},{b},会被多少个ccc计算到?
-
显然是∏i=1Kmin(ai,bi)\prod_{i=1}^K\min(a_i,b_i)∏i=1Kmin(ai,bi)
每一位iii都满足c[0][i]=c[1][i]≤min(ai,bi)c[0][i]=c[1][i]\le\min(a_i,b_i)c[0][i]=c[1][i]≤min(ai,bi)就行,因为ccc要求不能为000,而A,BA,BA,B要求可以为000
将每一位c[i]c[i]c[i]的可取值个数相乘,即是能利用A,BA,BA,B修补成{a},{b}\{a\},\{b\}{a},{b}的所有ccc的组合
于是乎,发现非常巧妙地将答案的乘积和转化成了计数个数贡献
再转个弯,我们直接计算每个特定的ccc会对多少个{a},{b}\{a\},\{b\}{a},{b}提供111的计数贡献,求和就等价于原问题的总贡献
然而,又发现了一个非常巧妙的性质,和(S)相同的ccc产生的计数贡献是一样的(但不是贡献的{a},{b}\{a\},\{b\}{a},{b}完全相同的意思)
-
要证明这个性质,就需要再转个弯,用到最开始的组合数推导
剩下的N−S,M−SN-S,M-SN−S,M−S都需要A,BA,BA,B的补给
A,BA,BA,B怎么补给,最后生成的{a},{b}\{a\},\{b\}{a},{b}会因此而固定
是一对一的关系
这个计数贡献自然是CS−1,K−1C_{S-1,K-1}CS−1,K−1
-
插板法
ccc的和为SSS,要求分成KKK个盒子,盒子不能为空
相当于有S−1S-1S−1个空位需要插入K−1K-1K−1个板
最后就成功不用生成函数解决这道题了!!!
现在总结,就只有一句话,最开始的c,A,Bc,A,Bc,A,B构造简直就是神来之笔
后面所有的推导全都是建立在最开始的规则设定基础上
真的妙极了!!
code
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define mod 998244353
#define maxn 1000005
int fac[maxn], inv[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}void init( int n ) {fac[0] = inv[0] = 1;for( int i = 1;i <= n;i ++ )fac[i] = fac[i - 1] * i % mod;inv[n] = qkpow( fac[n], mod - 2 );for( int i = n - 1;i;i -- )inv[i] = inv[i + 1] * ( i + 1 ) % mod;
}int C( int n, int m ) {return fac[n] * inv[m] % mod * inv[n - m] % mod;
}signed main() {init( 1e6 );int n, m, k, T;scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld %lld", &n, &m, &k );int ans = 0;for( int i = k;i <= min( n, m );i ++ )ans = ( ans + C( i - 1, k - 1 ) * C( n - i + k - 1, k - 1 ) % mod * C( m - i + k - 1, k - 1 ) ) % mod;printf( "%lld\n", ans );}return 0;
}