【jzoj3920】【噪音】【动态规划】

本文探讨了一道关于牛棚分配的算法题目,目标是通过合理使用清空操作来最小化牛进入牛棚产生的噪音总和。采用动态规划方法求解,并提供完整代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

FJ有M个牛棚,编号1至M,刚开始所有牛棚都是空的。FJ有N头牛,编号1至N,这N头牛按照编号从小到大依次排队走进牛棚,每一天只有一头奶牛走进牛棚。第i头奶牛选择走进第p[i]个牛棚。由于奶牛是群体动物,所以每当一头奶牛x进入牛棚y之后,牛棚y里的所有奶牛们都会喊一声“欢迎欢迎,热烈欢迎”,由于声音很大,所以产生噪音,产生噪音的大小等于该牛棚里所有奶牛(包括刚进去的奶牛x在内)的数量。FJ很讨厌噪音,所以FJ决定最多可以使用K次“清空”操作,每次“清空”操作就是选择一个牛棚,把该牛棚里所有奶牛都清理出去,那些奶牛永远消失。“清空”操作只能在噪音产生后执行。现在的问题是:FJ应该选择如何执行“清空”操作,才能使得所有奶牛进入牛棚后所产生的噪音总和最小?

解题思路

发现不同牛棚的牛互不影响,且牛都是等价的,可以把清空操作当成把牛分成若干堆,贡献只和牛的数量有关。考虑动态规划,f[i][j]表示到第i个牛棚用了k次清空的费用,把x只牛分成y堆尽量平均即是最优情况,具体算法可以自行思考,枚举每个棚用多少次机会即可。

code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxm=100,maxk=500;LL inf=1e18;
int n,m,K;LL f[maxm+10][maxk+10],s[maxm+10];
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);int x;
    fo(i,1,n)scanf("%d",&x),s[x]++;
    fo(i,0,m)fo(j,0,K)f[i][j]=inf;f[0][0]=0;
    fo(i,0,m-1)fo(j,0,K)if(f[i][j]!=inf)fo(k,0,K-j)
        f[i+1][j+k]=min(f[i+1][j+k],f[i][j]+(s[i+1]/(k+1)+1)*(s[i+1]/(k+1))/2*(k+1-s[i+1]%(k+1))+(s[i+1]/(k+1)+2)*(s[i+1]/(k+1)+1)/2*(s[i+1]%(k+1)));
    printf("%lld",f[m][K]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值