Codeforces Round #490 F. Cards and Joy (01背包)

传送门

题意:一共有n*k张卡牌,标有数字,n个人均分这些卡牌,每个人有自己的幸运数字f[i],当某人分得x张幸运数字卡牌,会获得h[x]点愉悦值,问所有人最大的愉悦值之和是多少。h[0]=0,保证h[i]<h[i+1]
(1<-n<=500,1<=k<=10)

分析:

  • 如果每个人的幸运数字都是不同的,那么先把幸运卡牌分给对应的人,然后多余卡牌随便分即可。
  • 但是可能有很多人有相同的幸运数字,所以我们需要考虑这样一个问题: num张卡牌 ,分给x个人,如何获得最大愉悦感之和? 很显然是个01背包问题。
  • 我们枚举每种幸运数字,dp[i][j]表示把j张 分给i个人的最优解 优化掉第一维
    dp[j]=max(dp[j],dp[j-t]+h[t]) 枚举t
  • 时间复杂度 O(n² * k²)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 1e5+10;
const int mx = 40;
const int mod = 1e9+7;
const ll inf = 34359738370;
const int INF = 1e9+7;
//给定n*k个卡牌 均分给n个人 每个人都有幸运数字 拿到x个幸运数字 获得h[x]点幸福值 h 递增 h[0]=0 
//幸福值之和的最大值
// 我们单独考虑每种幸运数字
//对于幸运数字L  num[L]个L 分配给 lover[l] 个人  最优解
//dp[i][j]=max(dp[i][j],dp[i-1][j-k]+h[k]) 枚举k
//dp[0][0]=0 dp[1][0]=0
int num[maxn];
int h[15];
int f[505];
int n,k;
int lover[maxn];//喜欢数字i的人数
int dp[maxn];
int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n*k;i++) 
    {
        int x;scanf("%d",&x);
        num[x]++;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",f+i);
        lover[f[i]]++;
    }
    for(int i=1;i<=k;i++) scanf("%d",h+i);
    ll ans=0;
    for(int x=1;x<=n;x++) //枚举每种幸运数字
    {
        int luck=f[x];
        if(!num[luck]) continue;//不存在卡牌 或者 已经分完了
        memset(dp,0,sizeof dp);//初始化
        for(int i=1;i<=lover[luck];i++) //枚举喜欢这种数字的人数
        {
            for(int j=num[luck];j>=1;j--) //倒序枚举卡牌个数
            {
                for(int t=0;t<=min(j,k);t++) //枚举k 第i个人分得t张,转移 wa点记得取min
                {
                    dp[j]=max(dp[j],dp[j-t]+h[t]);
                }
            }
        }
        ans+=dp[num[luck]];
        num[luck]=0;//分完了
    }
    cout<<ans;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值