把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

[ARC107D] Number of Multisets 分析

题目概述

你需要确定 \(n\) 个数,每个数形如 \(\frac{1}{2^x}(x\geq 0)\),其中 \(x\) 是非负整数,求他们的和为 \(k\) 的方案。

数据范围:\(1\leq k\leq n\leq 3000\)

分析

真的妙!

我们假设最后的结果为 \(\{\frac{1}{8},\frac{1}{2},\frac 1 2,1\}\)

我们可以看作一开始的序列为 \(\{1,1,1,1\}\),然后先对前 \(1\) 乘上两个 \(\frac{1}{2}\),再对前 \(3\) 个乘上 \(\frac{1}{2}\)

那么我们可以依据此设 \(f_{i,j}\) 表示前 \(i\) 个和为 \(j\) 的方案。

假设我当前只是放 \(1\),那么就是 \(f_{i,j}\leftarrow f_{i-1,j-1}\)

如果我要乘个若干个 \(\frac{1}{2}\),那么就是 \(f_{i,j}\leftarrow f_{i,2j}\)

为什么不是 \(f_{i-1,2j}\) 呢?因为我们这里可以乘很多个,这是一个完全背包。

代码

时间复杂度 \(\mathcal{O}(n^2)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 3005
using namespace std;
const int mod = 998244353;
int n,k;
int f[N][N];
signed main(){
    cin >> n >> k;
    f[0][0] = 1;
    for (int i = 1;i <= n;i ++)
        for (int j = i;j >= 0;j --) {
            f[i][j] = f[i - 1][j - 1];
            if (j * 2 <= i) f[i][j] = (f[i][j] + f[i][j * 2]) % mod;
        }
    cout << f[n][k];
    return 0;
}
posted @ 2025-11-10 19:37  high_skyy  阅读(7)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end