题目链接:
题目大意:
给定n和L,接下来n个数,第i个数 ai (0<=i<=n-1)代表购买 2i−1 个物品的花费,要求购买不少于L个的最小花费是多少
思路:
n,L的数值都比较大,使用多重背包不可行,观察题目可以发现,答案很可能与二进制位有关。可以想到, ai 与 ai+1 之间有三种关系
①2* ai = ai+1
②2* ai < ai+1
③2* ai > ai+1
在第一种关系下,无论是选择 ai 还是 ai+1 对答案没有影响
在第二种关系下,则应购买两个 ai 而不是一个 ai+1
在第三种关系下,应该选用 ai+1 而不是两个 ai
因此,我们可以得出购买 2k 件商品的最优解思考一个问题:假设恰好需要购买L件,而不是大于等于L件,这个时候,只要在以上的基础,把L对应二进制位上的 ai 全部加起来就是最优解。
当可以购买大于等于L件商品的时候的最优解:假设购买了M件商品为最优解,M>=L。此时从高位到低位,M与L的二进制第一次出现不同的位置i所对应的 ai 小于L比i小的所有位 ai 的和。从这个角度出发可得最优解。
代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long INF=9223372036854775807;
long long s[31];
long long dp[31];
long long a[31];
int main()
{
int n,L;
memset(a,0,sizeof a);
scanf("%d%d",&n,&L);
for(int i=0;i<n;i++)
{
scanf("%I64d",&dp[i]);
}
for(int i=0;i<n-1;i++)
{
dp[i+1]=min(dp[i+1],2*dp[i]);
}
long long ans=INF;
long long sum=0;
for(int i=n-1;i>=0;i--)
{
long long need=L/(1<<i);
sum+=need*dp[i];
L-= need<<i;
ans=min(ans,sum+(L>0)*dp[i]);/**(L>0)代表有余数,当前位的低位还有1**/
}
printf("%I64d\n",ans);
return 0;
}