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);
}
posted @ 2021-03-29 16:15  TRTTG  阅读(145)  评论(1编辑  收藏  举报