传送门 题意:给定两个整数 求 k 元组
的个数,满足
为正整数
且
均不是
的倍数
首先,如果没有 的限制,答案为
,插板,先全部减去1
考虑 的限制,发现不好容斥
发现最后的序列一定没有 m 的倍数,并且如果一个数 ,可以将它表示为
于是我们可以将最后的序列抽象为先选好 ,并强制让
,再对
随便加几个
枚举 ,
为上文所述的
,那么先选好的
的条件可以抽象为:
然后在对几个 加上
的倍数,假设
的范围内有
个 m 的倍数
发现这个过程等价于把 分到 k 个集合,可以为空,方案数为
如何求第一个,一下令 为
,考虑容斥,强制
个
但如何求强制 个
的个数呢,发现这个问题等价于选 i 个位置出来
,然后将
分配给这
个集合,最后再将这
个加上
,于是有
最后的答案,组合数暴力乘,有些不像
#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;
}