https://atcoder.jp/contests/arc116/tasks/arc116_c
经典不会组合
这题关键是想到对于dp[n][pi^ki],方案数是c(n-1+ki,n-1),就是你从(1,1)走到(n,ki)有多少种走法,而且可以连续增加ki,就相当于一次乘以pi的多次幂
然后线性筛预处理一下最小质因子,每次把最小质因数分解一下,然后递推就行了
也可以线性筛的时候记录一下最小质因子的幂次然后直接O(m)做,但还是O(mlogm)好写
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=4e5+10;
const int mod=998244353;
int n,m;ll ans;
int p[maxl],dy[maxl];
ll fac[maxl],inv[maxl],dp[maxl];
bool no[maxl];
inline void shai()
{
for(int i=2;i<maxl;i++)
{
if(!no[i]) p[++p[0]]=i,dy[i]=i;
int j=1,t=p[1]*i;
while(j<=p[0] && t<maxl)
{
no[t]=true;dy[t]=p[j];
if(i%p[j]==0)
break;
t=p[++j]*i;
}
}
}
inline ll qp(ll a,ll b)
{
ll ans=1,cnt=a;
while(b)
{
if(b&1) ans=ans*cnt%mod;
cnt=cnt*cnt%mod;
b>>=1;
}
return ans;
}
inline void prework()
{
shai();
fac[0]=1;
for(int i=1;i<maxl;i++)
fac[i]=fac[i-1]*i%mod;
inv[maxl-1]=qp(fac[maxl-1],mod-2);
for(int i=maxl-2;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
scanf("%d%d",&n,&m);
}
inline ll c(int n,int r)
{
if(r>n || r<0) return 0;
return fac[n]*inv[n-r]%mod*inv[r]%mod;
}
inline void add(ll &a,ll b){a=(a+b)%mod;}
inline void mainwork()
{
dp[1]=1;ans=1;
for(int i=2;i<=m;i++)
{
int x=i,d=dy[i],cnt=0;
while(x%d==0 && x>1)
cnt++,x/=d;
dp[i]=dp[x]*c(cnt+n-1,n-1)%mod;
add(ans,dp[i]);
}
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}