专栏文章

题解:P13521 [KOI 2025 #2] 包

P13521题解参与者 1已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miol7o32
此快照首次捕获于
2025/12/02 21:01
3 个月前
此快照最后确认于
2025/12/02 21:01
3 个月前
查看原文

0.更新日志

  • 2025.8.3:修正了一处笔误,并修改、润色内容。

1.题目思路

由于小偷会取 KK 个数且和最小,我们容易想到排序。先将原数列排序,此时前 KK 个数即为最小和。
但是,商户每次还会取出若干个(可能为零)物品装入包中。什么时候答案最大呢?
我们考虑维护一个指针 ll,指向当前商户决定是否带走的物品(在 ll 之前的物品一定会选,否则将留下小的数,不优),由于背包的容量是有限的,我们考虑把物品尽量装入背包,由于我们已经对数列排序,那么后面的数一定比前面的数大,所以答案更优。
但是,这个方法无法通过样例#3!为什么呢?考虑样例#3中,x=2x = 2 时,显然只装入第 11 个物品比装入前 22 个物品更优,而按照我们的思路却选择了后者。
此时,我们发现,商户不一定要把包装满。
由于 KK 的值不变,我们可以提前计算出数列中每 KK 个数(即 1K,2K+1,,NK+1N1 \sim K,2 \sim K+1,\cdots,N-K+1 \sim N)的和,计算答案时,在保证装入背包的物品重量不超过当前容量上限的情况下(利用前缀和数组 sumsum 解决,即 sum[l]\texttt{sum[l]}),找到所有满足条件的选法中的最大值并输出。
本题数据范围
十年OI一场空,(下一句你懂得)。
本题的前缀和数组,以及答案变量都需要开 long long\texttt{long long}

2.代码

注:代码仅供参考。
CPP
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int max_n=5005;
int n,k,c,a[max_n],l;
long long sum[max_n],ksum[max_n],ans; //开 long long!
int main(){
    scanf("%d %d %d",&n,&k,&c);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+n+1); //排序
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+a[i]; //计算前缀和
    }
    for(int i=k;i<=n;i++){
        ksum[i]=sum[i]-sum[i-k]; //K个数的和
    }
    for(int i=1;i<=c;i++){
        while(sum[l]<=i&&l<=n-k){ //保证满足条件时,计算最大值(注意一开始也有可能选 0 个)
            ans=max(ans,ksum[l+k]);
            l++; //指针
        }
        printf("%lld\n",ans); //输出
    }
    return 0;
}

3.后记

更多内容,请移步至:
  1. Luogu ryf2011\color{red}\texttt{Luogu ryf2011}
  2. cnblogs(博客园) cnblogs2011ryf\color{orange}\texttt{cnblogs(博客园) cnblogs2011ryf}

评论

1 条评论,欢迎与作者交流。

正在加载评论...