E. Modular Stability(组合数学&逆元)
结论: a 1 , a 2 … , a k a_1,a_2\dots,a_k a1,a2…,ak中 a 2 , a 3 , … , a k a_2,a_3,\dots,a_k a2,a3,…,ak必须是 a 1 a_1 a1的倍数才行。
证明:
反证法:若存在 a i , i ∈ [ 2 , k ] a_i,i\in[2,k] ai,i∈[2,k], a 1 ∤ a i a_1\nmid a_i a1∤ai
显然当 x = a i x=a_i x=ai时 ,当以 a k , a k − 1 … , a 1 a_k,a_{k-1}\dots,a_1 ak,ak−1…,a1排列时 a n s 1 = 0 ans_1=0 ans1=0.
当以 a 1 , a k , a k − 1 … , a 2 a_1,a_k,a_{k-1}\dots,a_2 a1,ak,ak−1…,a2排列时,显然有 a i m o d a 1 = t m p ≠ 0 a_i\bmod a_1=tmp\neq 0 aimoda1=tmp=0.
又因为 t m p < a 1 < a 2 ⋯ < a k tmp<a_1<a_2\dots<a_k tmp<a1<a2⋯<ak
所以 a n s 2 = t m p ≠ 0 ans_2=tmp\neq0 ans2=tmp=0
∴ a n s 1 ≠ a n s 2 \therefore ans_1\neq ans_2 ∴ans1=ans2
证毕。
所以对于最小数为 i i i的答案贡献为 C ( n i − 1 , k − 1 ) C(\dfrac{n}{i}-1,k-1) C(in−1,k−1)
i i i的倍数有 n i \dfrac{n}{i} in个,剩下可选的数有 n i − 1 \dfrac{n}{i}-1 in−1,然从这些数任选 k − 1 k-1 k−1个排好序即为一组。
即: a n s = ∑ ∀ { i ∣ n i − 1 ≥ k − 1 } C ( n i − 1 , k − 1 ) ans=\sum\limits_{\forall \{i|\frac{n}{i}-1\geq k-1\}}C(\dfrac{n}{i}-1,k-1) ans=∀{i∣in−1≥k−1}∑C(in−1,k−1)
组合数求逆元用线性递推或者费马小定理即可。
线性递推AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5,mod=998244353;
#define mst(a) memset(a,0,sizeof a)
ll fac[N],inv[N],fcinv[N];
ll C(int x,int y){//组合数取模
if(x<y) return 0;
else return (ll)fac[x]*fcinv[y]%mod*fcinv[x-y]%mod;
}
int main(){
int n,k;
scanf("%d%d",&n,&k);
fac[0]=fac[1]=inv[1]=fcinv[1]=fcinv[0]=1;
for(int i=2;i<=n;i++){
fac[i]=fac[i-1]*i%mod;//阶乘
inv[i]=(mod-mod/i)*inv[mod%i]%mod;//逆元递推
fcinv[i]=fcinv[i-1]*inv[i]%mod;//阶乘逆元
}
ll ans=0;
for(int i=1;i<=n;i++){
ans=(ans+C(n/i-1,k-1))%mod;
}
printf("%lld\n",ans);
return 0;
}
费马小定理AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5,mod=998244353;
#define mst(a) memset(a,0,sizeof a)
ll fac[N],inv[N];
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
int main(){
int n,k;
scanf("%d%d",&n,&k);
inv[0]=fac[0]=fac[1]=inv[1]=1;
for(int i=2;i<=n;i++){
fac[i]=fac[i-1]*i%mod;
}
ll ans=0;
for(int i=1;k-1<=n/i-1;i++){
ans=(ans+(fac[n/i-1])*ksm(fac[k-1]*fac[n/i-k]%mod,mod-2))%mod;
}
printf("%lld\n",ans);
return 0;
}