题目
HDU-6475-(三分+01背包 好题)Sample Input
1
3 5 1 5
-3 5 2
-2 2 3
2 5 3

Sample Output
9

思路:共有n个广告,一共有2^n个选择方案。假定确定好选择方案了。
利润: ka[x]+b[x]+ka[m]+b[m]+…+ka[r]+b[r]=k(a[x]+a[m]+…+a[r])+(b[x]+b[m]+b[r]);
每一种方案的利润对于k是一个一次函数。共有2^n个一次函数。对于确定的k,每个公司会选择 2 ^n种方案里面的最大利润。即2 ^n个 函数取最高值。将这2 ^n个函数画出来。
(利润关于k的图像)。将每个k对应的最高点连起来。可以看出是个凹函数。故三分得出答案。k对应这个凹函数的值(就是2 ^n个里面取最大值 用01背包完成)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define en '\n'
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=500+5,INF=0x3f3f3f3f;
int n,m,L,R;
ll a[N],b[N],w[N];
ll dp[N];
ll work(int k)
{
    m(dp,0);
    for(int i=1;i<=n;i++)
        for(int j=m;j>=w[i];j--)
            dp[j]=max(dp[j],dp[j-w[i]]+k*a[i]+b[i]);
    return dp[m];
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&m,&L,&R);
        for(int i=1;i<=n;i++)
            scanf("%lld%lld%lld",&a[i],&b[i],&w[i]);
        int l=L,r=R,m1,m2;
        while(r-l>1)
        {
            m1=(l+r)/2,m2=(m1+r)/2;
            if(work(m1)>work(m2))
                l=m1;
            else
                r=m2;
        }
        printf("%lld\n",work(r));
    }
}

相关文章: