题目:


思路:
依题意如果将mod的顺序任意变化,答案不变,那么所有数必须要是最小的数的倍数。假设模数没有倍数关系,那么连续取模就会破坏数据。问题取决于最小元素a[1]a[1]a[1],之后就是在a[1]a[1]a[1]的倍数中取k−1k-1k−1个,根据逆元组合数预处理出阶乘的逆元.
对阶乘的逆元有:inv[n!]=inv[(n+1)!]∗(n+1)%modinv[n!]=inv[(n+1)!]∗(n+1)\%modinv[n!]=inv[(n+1)!]∗(n+1)%mod
inv[n!]=1n!=(n!)mod−2%modinv[n!]=\frac{1}{n!}=(n!)^{mod-2}\%modinv[n!]=n!1=(n!)mod−2%mod
=1(n+1)!∗(n+1)=((n+1)!mod−2%mod)∗(n+1)=\frac{1}{(n+1)!}*(n+1)=((n+1)!^{mod-2}\%mod)*(n+1)=(n+1)!1∗(n+1)=((n+1)!mod−2%mod)∗(n+1)
=inv[(n+1)!]∗(n+1)%mod=inv[(n+1)!]*(n+1)\%mod=inv[(n+1)!]∗(n+1)%mod
测试一:
7 3
16
分析:
n=7,也就是从1,2,3,4,5,6,7中拿出k个成倍数关系的数字
当最小数a[1]=1的时候,从剩下的a[1]的倍数(n/1-1=6)中拿出(k-1=2)个数,有C62=15C_{6}^{2}=15C62=15
当最小数a[1]=2的时候,从剩下的a[1]的倍数(n/2-1=2)中拿出(k-1=2)个数,有C22=1C_{2}^{2}=1C22=1
当最小数a[1]=3的时候,从剩下的a[1]的倍数(n/3-1=1)中拿出(k-1=2)个数,有C12=0C_{1}^{2}=0C12=0
…
综上n=7,k=3的时候,有15+1=16种可能
我们可以推导出最终的结果为∑i=1nCni−1k−1\sum_{i=1}^{n}C_{\frac{n}{i}-1}^{k-1}∑i=1nCin−1k−1
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353,maxn=5e5+5;
ll inv[maxn],fac[maxn],n,k,ans=0;
ll qpow(ll a,ll b) { //快速幂模板
ll res = 1,base = a;
while(b) {
if(b&1) res = res*base%mod;
base = base*base%mod;
b >>= 1;
}
return res;
}
void init() { //初始化 求阶乘和阶乘的逆元
fac[0]=1;
for(int i=1; i<maxn; i++) fac[i]=(fac[i-1]*i)%mod;
int t=5e5;
inv[t]=qpow(fac[t],1LL*(mod-2))%mod;
for(int i=t-1; i>=0; i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll x,ll y) { //组合数模板
if(x<y) return 0;
ll res=1;
y=min(x-y,y);
for(int i=x; i>=x-y+1; i--) res=res*i%mod;
res=res*inv[y]%mod;
return res;
}
int main() {
cin>>n>>k;
init();
for(int i=1; i<=n; i++) ans=(ans+C(n/i-1,k-1))%mod;
cout<<ans<<endl;
}
本文探讨了在特定模数关系下,寻找成倍数关系数字组合的问题。通过分析最小元素及其倍数,利用逆元组合数预处理,解决了在一定范围内找出k个数的成倍数关系组合数目。介绍了快速幂、阶乘及其逆元的计算方法,并提供了AC代码实现。
350

被折叠的 条评论
为什么被折叠?



