洛谷P7223 [RC-04] 01 背包

[RC-04] 01 背包

题目描述

P7223 [RC-04] 01 背包 - 洛谷

‘有一个容积为 + 的背包,你要往里面放物品。

你有 n 个物品,第 i 个体积为 ai

你有一个幸运数字 p,若放入的物品体积和为 k,你会得到 pk 的收益。特别地,00=1

求所有 2n 种放入物品的方案的收益和。答案很大,因此请输出它对 998244353 取模的值。

输入格式

第一行两个整数 n,p

接下来一行 n 个正整数 a1an,描述这 n 个物品的体积。

输出格式

输出一个整数,为所有 2n 种方案的收益和对 998244353 取模的值。

样例 #1

样例输入 #1

2 2
1 4

样例输出 #1

51

提示

【样例解释】

答案为 20+21+24+25=51

【数据范围】

对于所有数据,1n1060p,ai<998244353

详细数据范围如下表:

测试点编号 n p i=1nai 每测试点分数
1 =0 2
25 22 6
69 1000 1000 6
1014 100000 100000 5
15 25

解析

递归枚举所有方案

所有的方案个数为 nums21000000

理想情况下,最多只能拿到测试点编号2~5的分数

注意要对MOD使用finnal关键字

java中final 与效率_fa1d1的博客

import java.util.Scanner;

public class Main {
    static Scanner sc = new Scanner(System.in);
    static int n;
    static int p;
    static int[] w;
    static long ans = 0;
    static final int MOD = 998244353;//一定要用final关键字!!!
    public static void main(String[] args) {
        n = sc.nextInt();
        p = sc.nextInt();
        w = new int[n];
        for (int i = 0; i < n; ++i) {
            w[i] = sc.nextInt();
        }
        dfs(0,0);
        System.out.println(ans);
    }
    static void dfs(int len, long sum) {
        if (len == n) {
            ans = (ans + pow(p, sum)) % MOD;
            return;
        }
        dfs(len + 1, sum);//如果不选择当前物品
        dfs(len + 1, sum + w[len]);//如果选择当前物品
    }
    static long pow(long x, long n) {//尽量使用位运算优化
        long ans = 1;
        for (; n != 0; n >>= 1, x = x * x % MOD) {
            if ((n & 1) == 1) ans = ans * x % MOD;
        }
        return ans;
    }
}

数学推导

X个物品的总收益记为ansx,前X1个物品的总收益记为ansx1

以下关注ansx的性质

设每种方案的总体积为ki,其中 iϵ[1,2x]

ansx=i=12xpki

对于所有方案都增加V体积

则总收益变为i=12xpki+V=pV×i=12xpki=pV×ansx

所以,若每种方案的体积都增加V,相当于乘以pV

考虑第X个物品的 ansx

每种物品仅有两种情况

  1. 不选该物品,由于任意一种方案的物品总体积不变,则对ansx1无影响
  2. 选择该物品,对任意一种方案的物品总体积增加Vx,则ansx1×pVx

ansx为这两种情况的价值的和

ansx=ansx1+ansx1×pVx=ansx1×(1+pVx)

ansxansx1=1+pVx

由累乘法得:ansxans0=i=1x(1+pVi)

ans0表示当前无任何物品,即V=0

ans0=pV=p0=1

ansx=i=1x(1+pVi)

import java.util.Scanner;

public class Main {
    static Scanner sc = new Scanner(System.in);
    static final long MOD = 998244353;
    static int n;
    static long ans = 1l, p;
    static int[] V;

    static long powMod(long a, int b) {
        long ret = 1;
        for (; b != 0; b >>= 1, a = a * a % MOD)
            if ((b & 1) == 1) ret = ret * a % MOD;
        return ret;
    }

    public static void main(String[] args) {
        n = sc.nextInt();
        p = sc.nextLong();
        V = new int[n];
        for (int i = 0; i < n; ++i) V[i] = sc.nextInt();
        for (int v : V) ans = ans * (1l + powMod(p, v)) % MOD;
        System.out.println(ans);
    }
}
posted @   Cattle_Horse  阅读(116)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示