ARC116 C - Multiple Sequences【组合数学/DP】

10 篇文章 0 订阅
2 篇文章 0 订阅

Link

题目

给出一个 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) 1AiM(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,,N1)

结果取模 998244353 998244353 998244353 1 ≤ N , M ≤ 2 × 1 0 5 1\leq N,M \leq 2\times 10^5 1N,M2×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} Ai1 的基础上乘上 p i k p_i^k pik k k k 表示可以放多个)。另外注意是 n 个位置不是 n − 1 n-1 n1,因为质因子的个数不一定要用完。自此,问题转化为将 e e e 个相同的物体放入 n n n 个不同的盒子且盒子可以空的问题模型,答案是 ( n + e − 1 e ) \left(\begin{matrix} n+e-1\\ e\end{matrix}\right) (n+e1e)。最后的复杂度为 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值