题目
给出一个 n n n 和 m m m,求出满足下列要求的序列的个数:
- 1 ≤ A i ≤ M ( i = 1 , 2 , ⋯ , N ) 1\leq A_i \leq M(i=1,2,\cdots,N) 1≤Ai≤M(i=1,2,⋯,N)
- A i + 1 A_{i+1} Ai+1 是 A i A_i Ai 的倍数 ( i = 1 , 2 , ⋯ , N − 1 ) (i=1,2,\cdots,N-1) (i=1,2,⋯,N−1)
结果取模 998244353 998244353 998244353, 1 ≤ N , M ≤ 2 × 1 0 5 1\leq N,M \leq 2\times 10^5 1≤N,M≤2×105。
分析
组合数学解法
考虑枚举 A n A_n An 的值,然后把所有取值的方案加起来。假设 A n = x A_n=x An=x,为了满足性质 2 2 2,对 x x x 进行质因子分解,得到每个质因子 p i p_i pi 及其幂 e i e_i ei。对每个质因子分别考虑,然后把每个质因子的结果乘起来。对于 e i e_i ei 个质因子 p i p_i pi,需要把它放置在 n n n 个位置中(放置在第 i i i 个位置表示 A i A_i Ai 的值在 A i − 1 A_{i-1} Ai−1 的基础上乘上 p i k p_i^k pik, k k k 表示可以放多个)。另外注意是 n 个位置不是 n − 1 n-1 n−1,因为质因子的个数不一定要用完。自此,问题转化为将 e e e 个相同的物体放入 n n n 个不同的盒子且盒子可以空的问题模型,答案是 ( n + e − 1 e ) \left(\begin{matrix} n+e-1\\ e\end{matrix}\right) (n+e−1e)。最后的复杂度为 O ( m log 2 m ) O(m\log_2m) O(mlog2m)。预处理阶乘和阶乘逆元计算组合数时,处理的范围要大于 N N N。
代码
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int N=2e5+200;
ll fac[N],inv[N];
ll power(ll x,int y){
ll res=1;
while(y){
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
void init(){
int maxn=2e5+100;//要比2e5大
fac[0]=1;
for(int i=1;i<=maxn;i++) fac[i]=fac[i-1]*i%mod;
inv[maxn]=power(fac[maxn],mod-2);
for(int i=maxn-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll solve(int a,int b){
if(b>a||b<0) return 0;
ll res=fac[a]*inv[b]%mod*inv[a-b]%mod;
return res;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
ll ans=0;
init();
for(int i=1;i<=m;i++){//枚举A[n]
int x=i;
ll res=1;
vector<int>p;
for(int j=2;1LL*j*j<=x;j++){
if(x%j==0){
int cnt=0;
while(x%j==0){
x/=j;
cnt++;
}
p.push_back(cnt);
}
}
if(x>1) p.push_back(1);
for(auto e:p)
res=res*solve(n+e-1,e)%mod;
ans=(ans+res)%mod;
}
printf("%lld\n",ans);
return 0;
}