1 条题解

  • 0
    @ 2026-5-5 18:26:17

    首先我们设 f(i,j,k)f(i,j,k) 表示前 ii 项还剩 jj 元和 kk 个冰淇淋的最大受欢迎程度,简单分析,这样做时间复杂度为 O(n4)O(n^4) 级别的,无法通过本题。

    我们可以感性理解一手,其实是因为我也没理解透,不难发现冰淇淋并不是另外一个需要考虑的量,而是一个可以代替钱的优惠券。

    彬彬跟我聊天的时候给出了一个比喻:我们换钱的时候,总是考虑去汇率更大的银行换钱。

    因此,这道题我们可以考虑以“贿赂”所需的冰淇淋的数量从小到大排序,前面的朋友等同于汇率更大的银行。

    我们在前面用冰淇淋肯定比在后面用好。

    简单证明一下,如果我们在后面用了冰淇淋,前面用了钱,可以将后面的冰淇淋换成钱,把前面的钱换成冰淇淋,这样钱数不变,花费的冰淇淋变少。

    我们考虑枚举一个中间点,中间点以上全部使用冰淇淋,中间点以下全部使用钱,中间点两者皆可,求出最大受欢迎程度即可。

    这就拆成了两个背包。

    时间复杂度降为 O(n2)O(n^2)

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const LL N=2e3+5;
    struct node
    {
    	LL p,c,x;
    }a[N];
    LL n,m,k,f[N][N],g[N][N],ans;
    bool cmp(node x,node y)
    {
    	return x.x<y.x;
    }
    int main()
    {
    	scanf("%lld%lld%lld",&n,&m,&k);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%lld%lld%lld",&a[i].p,&a[i].c,&a[i].x);
    	}
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=n;i++)
    	{
    		LL p=a[i].p,c=a[i].c*a[i].x;
    		for(int j=0;j<=c-1&&j<=k;j++)
    		{
    			f[i][j]=f[i-1][j];
    		}
    		for(int j=c;j<=k;j++)
    		{
    			f[i][j]=max(f[i-1][j],f[i-1][j-c]+p);
    		}
    	}
    	for(int i=n;i>=1;i--)
    	{
    		LL p=a[i].p,c=a[i].c;
    		for(int j=0;j<=c-1;j++)
    		{
    			g[i][j]=g[i+1][j];
    		}
    		for(int j=c;j<=m;j++)
    		{
    			g[i][j]=max(g[i+1][j],g[i+1][j-c]+p);
    		}		
    	}
    	for(LL i=1;i<=n;i++)
    	{
    		for(LL j=0;j<=a[i].c&&j<=m;j++)
    		{
    			if((a[i].c-j)*a[i].x>k)continue;
    			ans=max(ans,f[i-1][k-(a[i].c-j)*a[i].x]+a[i].p+g[i+1][m-j]);
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
    • 1

    信息

    ID
    7606
    时间
    2000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    23
    已通过
    7
    上传者