比赛结束后20分钟de出bug,身心憔悴
A New Year party is not a New Year party without lemonade! As usual, you are expecting a lot of guests, and buying lemonade has already become a pleasant necessity.
Your favorite store sells lemonade in bottles of n different volumes at different costs. A single bottle of type i has volume 2i - 1 liters and costs ci roubles. The number of bottles of each type in the store can be considered infinite.
You want to buy at least L liters of lemonade. How many roubles do you have to spend?
The first line contains two integers n and L (1 ≤ n ≤ 30; 1 ≤ L ≤ 109) — the number of types of bottles in the store and the required amount of lemonade in liters, respectively.
The second line contains n integers c1, c2, ..., cn (1 ≤ ci ≤ 109) — the costs of bottles of different types.
Output a single integer — the smallest number of roubles you have to pay in order to buy at least L liters of lemonade.
4 12 20 30 70 90
150
4 3 10000 1000 100 10
10
4 3 10 100 1000 10000
30
5 787787787 123456789 234567890 345678901 456789012 987654321
44981600785557577
In the first example you should buy one 8-liter bottle for 90 roubles and two 2-liter bottles for 30 roubles each. In total you'll get 12 liters of lemonade for just 150 roubles.
In the second example, even though you need only 3 liters, it's cheaper to buy a single 8-liter bottle for 10 roubles.
In the third example it's best to buy three 1-liter bottles for 10 roubles each, getting three liters for 30 roubles.
思路:刚看到这到题以为是完全背包,然后发现数据有点大,想着模拟发现好像bug有点多,就在快要放弃的时候,突然想到ci都是2的i次幂,莫不是有什么关系。
然后想到2进制好像能表示所有的数,那么应该可以dp得到2进制每一位的最小价格。再将L拆成二进制数。然后计算相加之和。
但是有两点问题:
1. 011 需要的价值可能比 100 需要价值高,第四组样例就是这样。
2. 最小的价值可能出现在 二进制1最高位的后一位。
——————————————————————————————————
看dalao代码只能感叹,卧槽这是什么操作,卧槽这又是什么操作,卧槽还有这种操作!ORZ
代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<queue>
using namespace std;
#define eps 1e-8
#define mod 1000000007
#define ll long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
ll v[100];
ll dp[1000],www[1000];
int main(){
ll n,L,i,index=0;
scanf("%lld%lld",&n,&L);
for(i=0;i<n;i++)scanf("%lld",&v[i]);
mem(www,0);
//得到L的二进制
while(L){
if(L%2)www[index]=1;
index++;
L/=2;
}
//得到每一位二进制的最小价格
dp[0]=v[0];
//i<n也可以不然可能再后面出现更优价格
//i<=index是为了多得到一位
for(i=1;i<=index||i<n;i++){
if(i<n){
dp[i]=min(2*dp[i-1],v[i]);
for(int j=0;j<i;j++)
if(dp[j]>v[i])dp[j]=dp[i];
}
else dp[i]=2*dp[i-1];
}
//如果前面各位需要价值之和 小于 当前位,只需购买当前位即可
for(i=0;i<=index;i++){
ll ans=0;
for(ll j=0;j<i;j++){
ans+=dp[j]*www[j];
}
if(ans>dp[i]){
for(ll j=0;j<i;j++)
www[j]=0;
www[i]++;
}
}
//for(i=0;i<=index||i<n;i++)printf("%lld\n",dp[i]);
//for(i=0;i<=index;i++)printf("%lld\n",www[i]);
ll ans=0;
//经过前面操作最高为1可能向后延续了一位,没延续后面本来就是0也不影响
for(i=0;i<=index;i++)
ans+=dp[i]*www[i];
//答案可能存在于当前最高位后一位
if(www[i])if(ans>dp[i]*www[i])ans=dp[i]*www[i];
printf("%lld\n",ans);
return 0;
}