AtCoder Regular Contest 116 C - Multiple Sequences
https://atcoder.jp/contests/arc116/tasks/arc116_c
题意:
给出2个正整数n和m
问能构造出多少个长为n的序列a,满足1<=ai<=m且a[i]%a[i-1]=0
因为a[i]%a[i-1]=0
所以这个序列是不降序列
进一步可以得出不同的数字个数不会超过\(\log_2 m\)个
\(\log_2 m\)比较小(大约18),可以考虑从这一点出发寻找答案
假设我们已经确定好要用哪k种数
这k种数只能按从小到大的顺序排列成长为n的序列
序列个数相当于在n-1个空隙中插入k-1个隔板,将n个数分为k部分
所以是\(C_{n-1}^{k-1}\)种
那么如果我们能够计算出\(sum[i]\)表示在1-m中选出i个数,满足后一个对前一个取模等于0 的选法数量
那么答案就等于\(\sum_{i=1}^{min(n,(log_2 m)+1)}{sum[i]*C_{n-1}^{i-1}}\)
\(sum[i]\)怎么求?
令\(f[i][j]\)表示在1-i中选了j个数,满足后一个对前一个取模等于0且i必选的方案数
枚举i的倍数转移
\(f[i*k][j+1]+=f[i][j]\)
最后\(sum[i]=\sum_{j=1}^{min(n,(log_2 m)+1)}{f[j][i]}\)
#include<cstdio>
const int mod=998244353;
#define N 200001
int f[N][20],sum[N];
int fac[N],inv[N];
int pow2(int a,int b)
{
int c=1;
for(;b;a=1ll*a*a%mod,b>>=1)
if(b&1) c=1ll*c*a%mod;
return c;
}
int C(int n,int m)
{
return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i) f[i][1]=1;
for(int i=1;i<=m;++i)
for(int j=1;j<20;++j)
for(int k=i+i;k<=m;k+=i)
{
f[k][j+1]+=f[i][j];
if(f[k][j+1]>=mod) f[k][j+1]-=mod;
}
fac[0]=1;
inv[0]=1;
for(int i=1;i<=n;++i)
{
fac[i]=1ll*fac[i-1]*i%mod;
inv[i]=pow2(fac[i],mod-2);
}
int p=19;
if(p>n) p=n;
for(int i=1;i<=p;++i)
for(int j=1;j<=m;++j)
{
sum[i]+=f[j][i];
if(sum[i]>=mod) sum[i]-=mod;
}
int ans=0;
for(int i=1;i<=p;++i)
{
ans+=1ll*sum[i]*C(n-1,i-1)%mod;
if(ans>=mod) ans-=mod;
}
printf("%d",ans);
}