传送门
题意:给定两个整数
n
,
m
n, m
n,m 求 k 元组
(
a
1
,
a
2
,
…
,
a
k
)
(a1,a2,…,ak)
(a1,a2,…,ak) 的个数,满足
a
1
,
a
2
,
…
,
a
k
a1,a2,…,ak
a1,a2,…,ak 为正整数
∑
a
i
=
n
\sum a_i=n
∑ai=n 且
a
1
,
a
2
,
…
,
a
k
a1,a2,…,ak
a1,a2,…,ak 均不是
m
m
m的倍数
n
≤
1
e
18
,
m
≤
5
e
3
,
k
≤
2
e
3
n\le 1e18,m\le5e3,k\le2e3
n≤1e18,m≤5e3,k≤2e3
首先,如果没有
m
m
m 的限制,答案为
(
n
−
1
k
−
1
)
\binom{n-1}{k-1}
(k−1n−1),插板,先全部减去1
考虑
m
m
m 的限制,发现不好容斥
发现最后的序列一定没有 m 的倍数,并且如果一个数
≥
m
\ge m
≥m ,可以将它表示为
r
+
k
m
r+km
r+km
于是我们可以将最后的序列抽象为先选好
a
1
,
a
2
,
.
.
.
,
a
k
a_1,a_2,...,a_k
a1,a2,...,ak,并强制让
a
i
<
m
a_i<m
ai<m,再对
a
i
a_i
ai 随便加几个
m
m
m
枚举
∑
r
i
=
S
\sum r_i = S
∑ri=S,
r
r
r 为上文所述的
r
r
r,那么先选好的
a
1
,
a
2
,
.
.
.
,
a
k
a_1,a_2,...,a_k
a1,a2,...,ak 的条件可以抽象为:
- ∑ a i = S \sum a_i = S ∑ai=S
- a i ≤ m − 1 a_i \le m-1 ai≤m−1
然后在对几个
a
i
a_i
ai 加上
m
m
m 的倍数,假设
≤
n
\le n
≤n 的范围内有
c
c
c 个 m 的倍数
发现这个过程等价于把
c
c
c 分到 k 个集合,可以为空,方案数为
(
c
+
k
−
1
k
−
1
)
\binom{c+k-1}{k-1}
(k−1c+k−1)
如何求第一个,一下令
m
m
m 为
m
−
1
m-1
m−1,考虑容斥,强制
i
i
i 个
>
m
>m
>m
但如何求强制
i
i
i 个
>
m
>m
>m 的个数呢,发现这个问题等价于选 i 个位置出来
>
m
> m
>m,然后将
n
−
i
∗
m
n-i*m
n−i∗m 分配给这
k
k
k 个集合,最后再将这
i
i
i 个加上
m
m
m,于是有
f
(
n
,
m
,
k
)
=
∑
i
=
0
k
(
−
1
)
i
(
k
i
)
(
n
−
i
∗
m
−
1
k
−
1
)
f(n,m,k)=\sum_{i=0}^k(-1)^i\binom{k}{i}\binom{n-i*m-1}{k-1}
f(n,m,k)=i=0∑k(−1)i(ik)(k−1n−i∗m−1)
最后的答案
a
n
s
=
∑
i
=
0
k
f
(
i
∗
m
+
n
%
m
,
m
−
1
,
k
)
∗
(
n
m
−
i
+
k
−
1
k
−
1
)
ans=\sum_{i=0}^k f(i*m+n\%m,m-1,k)*\binom{\frac{n}{m}-i+k-1}{k-1}
ans=i=0∑kf(i∗m+n%m,m−1,k)∗(k−1mn−i+k−1)
n
≤
1
e
18
n\le 1e18
n≤1e18,组合数暴力乘,有些不像
T
1
T1
T1
#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
ll read(){
ll cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e7 + 5;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b);}
ll n; int m, k, fac[N], inv[N];
int C(ll n, int m){
if(n < 0 || m < 0 || n < m) return 0;
if(n < N) return mul(fac[n], mul(inv[m], inv[n - m]));
else{
int ret = inv[m];
for(ll i = n; i >= n - m + 1; i--) ret = mul(ret, i % Mod);
return ret;
}
}
int g(ll n, int m){
// devide n into m group and the group can be empty
if(n < 0) return 0;
return C(n + m - 1, m - 1);
}
int f(int n, int m, int k){
// devide n into m group that the size of each group is less than k
// can not be empty
n -= m; if(n < 0) return 0;
int ans = 0;
for(int i = 0; i <= m; i++){
int ret = mul(g(n - i * k, m), C(m, i));
(i & 1) ? Add(ans, Mod - ret) : Add(ans, ret);
} return ans;
}
int main(){
n = read(), m = read(), k = read();
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i = 2; i < N; i++) fac[i] = mul(fac[i-1], i);
for(int i = 2; i < N; i++) inv[i] = mul(Mod-Mod/i, inv[Mod%i]);
for(int i = 2; i < N; i++) inv[i] = mul(inv[i], inv[i-1]);
// 枚举 < m 的数的和
ll r = n % m; int ans = 0;
for(int i = 0; i < k; i++){
Add(ans, mul(f(i * m + r, k, m - 1), g((n - r) / m - i, k)));
} cout << ans; return 0;
}