牛客练习赛36-C: Rabbit的工作(2)(快速幂优化DP)

本文介绍了一种优化的动态规划算法,用于解决Rabbit如何在满足boss要求的天数内,通过合理安排任务完成时间来最大化boss满意度的问题。算法采用类似于多重背包的二进制优化方式,显著提高了效率。

链接:https://ac.nowcoder.com/acm/contest/328/C

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
Rabbit通过了上次boss的考核,现在她又遇到了一个问题。
Rabbit接到了K个任务,每个任务她可以自由选择用i天去完成 ( 1 ≤ i ≤ N ) (1≤ i≤ N) (1iN)。刁钻的boss想让Rabbit恰好用W天完成所有任务。
已知Rabbit用i天完成一个任务能让boss获得的满意度为 v i v_i vi(因为完成任务的质量不同),她想知道在满足boss要求的情况下能让boss获得的总满意度最大是多少。
输入描述:
第一行三个整数N,K,W。
第二行N个整数 v i , v i v_i,v_i vivi表示用i天完成一个任务能让boss获得的满意度。
输出描述:
输出Rabbit在满足boss要求的情况下能让boss获得的总满意度最大是多少。
示例1
输入
3 3 5
6 2 4
输出
16
说明
Rabbit可以选择分别用1天,1天,3天完成这三个任务,最大满意度为6+6+4=16
备注:
2 ≤ N , K ≤ 2000 , K ≤ W ≤ m i n ( 4000 , 2 ∗ K ) 2≤ N,K≤ 2000,K≤ W≤ min(4000,2*K) 2N,K2000,KWmin(4000,2K)
0 &lt; v i ≤ 10000 0&lt;v_i≤ 10000 0<vi10000

思路:容易想到一个 n 3 n^3 n3的算法, d [ i ] [ j ] d[i][j] d[i][j]表示前 i i i个任务总共花了 j j j天去完成的最大满意度。
需要优化。
因为 O ( n 3 ) O(n^3) O(n3)的DP是一个任务一个任务去转移的,所以我们考虑用快速幂的方式进行加速。即第一次转移选择一个任务,第二次选择两个任务,第三次选择四个任务。。。以此类推,比较类似多重背包的二进制优化。

#include<bits/stdc++.h>
using namespace std;
const int MAX=4e3+10;
const int MOD=1e9+7;
const int INF=1e9+7;
typedef long long ll;
int d[2][MAX];
int res[2][MAX];
int a[MAX];
int main()
{
    int n,m,w;
    cin>>n>>m>>w;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    memset(d,0,sizeof d);
    for(int i=0;i<=w;i++)res[0][i]=res[1][i]=-INF;
    res[0][0]=0;
    d[0][0]=-INF;
    for(int i=1;i<=n;i++)d[0][i]=a[i];
    int now=1,pre=0;
    while(m)
    {
        if(m&1)
        {
            for(int i=w;i>=0;i--)
            {
                res[now][i]=-INF;
                for(int j=0;j<=i;j++)res[now][i]=max(res[now][i],d[pre][j]+res[pre][i-j]);
            }
        }
        else for(int i=w;i>=0;i--)res[now][i]=res[pre][i];
        for(int i=w;i>=0;i--)
        {
            d[now][i]=-INF;
            for(int j=0;j<=i;j++)d[now][i]=max(d[now][i],d[pre][j]+d[pre][i-j]);
        }
        m/=2;
        pre^=1;
        now^=1;
    }
    cout<<res[pre][w]<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值