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 a1ai

显然当 x = a i x=a_i x=ai时 ,当以 a k , a k − 1 … , a 1 a_k,a_{k-1}\dots,a_1 ak,ak1,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,ak1,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(in1,k1)

i i i的倍数有 n i \dfrac{n}{i} in个,剩下可选的数有 n i − 1 \dfrac{n}{i}-1 in1,然从这些数任选 k − 1 k-1 k1个排好序即为一组。

即: 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={iin1k1}C(in1,k1)

组合数求逆元用线性递推或者费马小定理即可。

线性递推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;
}