链接
https://ac.nowcoder.com/acm/contest/9985/B
题意
给定 n , m n,m n,m,定义一种序列,构造方法如下:
- 在 [ 1 , n ] [1,n] [1,n] 中任意选择 m m m 次,得到了 m m m 个整数(显然数字可能相同);
- 将选出的 m m m 个数字排序之后得到一个序列 { a 1 , a 2 , . . . , a m } \{ a_{1},a_{2},...,a_{m} \} {a1,a2,...,am}
定义一个序列的贡献为 max { a 1 , a 2 , . . . , a m } − min { a 1 , a 2 , . . . , a m } \max\{ a_{1},a_{2},...,a_{m} \}-\min\{ a_{1},a_{2},...,a_{m} \} max{a1,a2,...,am}−min{a1,a2,...,am},求所有不同的序列的贡献和。
思路
本题顺序不同元素相同的序列是等价的,所以直接考虑非降序列。
枚举差值 d d d,最小数有 n − d n-d n−d 种取法,考虑查分序列。
我们要求的是从 0 ∼ d 0\sim d 0∼d 中选出 m − 1 m-1 m−1个数(可相同),使差分序列前缀和等于 d d d 的方案数 ,
即将 d d d 个相同的球放入 m − 1 m-1 m−1 个不同的盒子,并允许空盒子的方案数 ,
等价于将 d + m − 1 d+m-1 d+m−1 个相同的球放入 m − 1 m-1 m−1 个不同的盒子,不允许空盒子的方案数 ,
所以 f ( d , m − 1 ) = ( d + m − 2 m − 2 ) f(d,m-1)=\binom{d+m-2}{m-2} f(d,m−1)=(m−2d+m−2), r e s = ∑ d = 0 n − 1 d ∗ ( n − d ) ∗ f ( d , m − 1 ) res=\sum_{d=0}^{n-1}{d*(n-d)*f(d,m-1)} res=∑d=0n−1d∗(n−d)∗f(d,m−1)。
代码
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
// head
const LL MOD=998244353;
const int N=1e6+5;
LL fac[N],invfac[N];
LL qpow(LL a,LL b) {
LL ret=1;
while(b) {
if(b&1) ret=ret*a%MOD;
a=a*a%MOD;
b>>=1;
}
return ret;
}
void init_invfac(int n) {
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
invfac[n]=qpow(fac[n],MOD-2);
for(int i=n-1;~i;i--) invfac[i]=invfac[i+1]*(i+1)%MOD;
}
LL C(int a,int b) {
return fac[a]*invfac[b]%MOD*invfac[a-b]%MOD;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
init_invfac(n+m);
LL res=0;
for(int i=0;i<n;i++) res=(res+(n-i)*i%MOD*C(i+m-2,m-2)%MOD)%MOD;
cout<<res<<'\n';
return 0;
}