题目描述:
On his trip to Luxor and Aswan, Sagheer went to a Nubian market to buy some souvenirs for his friends and relatives. The market has some strange rules. It contains n different items numbered from 1 to n. The i-th item has base cost ai Egyptian pounds. If Sagheer buys kitems with indices x1,?x2,?...,?xk, then the cost of item xj is axj?+?xj·k for 1?≤?j?≤?k. In other words, the cost of an item is equal to its base cost in addition to its index multiplied by the factor k.
Sagheer wants to buy as many souvenirs as possible without paying more than S Egyptian pounds. Note that he cannot buy a souvenir more than once. If there are many ways to maximize the number of souvenirs, he will choose the way that will minimize the total cost. Can you help him with this task?
输入描述:
The first line contains two integers n and S (1?≤?n?≤?105 and 1?≤?S?≤?109) — the number of souvenirs in the market and Sagheer‘s budget.
The second line contains n space-separated integers a1,?a2,?...,?an (1?≤?ai?≤?105) — the base costs of the souvenirs.
输出描述:
On a single line, print two integers k, T — the maximum number of souvenirs Sagheer can buy and the minimum total cost to buy these ksouvenirs.
样例输入1:
3 11
2 3 5
样例输出1:
2 11
样例输入2:
4 100
1 2 5 6
样例输出2:
4 54
样例输入3:
1 7
7
样例输出3:
0 0
题目大意:
你只带了m元钱去市场买东西,市场有n件物品,每一件物品的基本价格为a1,a2,....an,而当你最终决定买k件物品时,每一件物品的价格还得在基本价格上加上i * k元,其中,i为物品的下标,k是可以变得,现在你的任务是,尽量购买多一点物品,当购买物品数量一样的方法有很多的情况下,使花的价格最少。
输入解释:
输入两行。
第一行为两个整数,第一个整数为市场上物品的总数量,第二个整数为你的预算
第二行为这n件物品的基本价格
输出解释:
输出两个证整数,第一个整数为你能购买物品的最大数量,第二个整数为购买这个数量的物品所花的最少价格。
题目分析:
这道题目既然是让我们找最大数量,我们就很容易的想到需要二分答案,而二分的标准是啥?自购买物品的数量,然是数量,我们可以这样想:假设k为我们最终我们购买物品的数量,那么0<=k<=n,我们只需要不断二分k,再在当数量为k的时候去购买价格最低的k件物品,如果预算可以购买这k件物品,就代表这个数量可行,我们保存这个结果,然后从k+1数量到n数量继续二分,否则,我们从0数量到k-1数量二分找可行的数量。分析到这里,思路应该就出来了吧?下面上代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const long long int N = 100001;
long long int a[N],b[N],n,m,sum = 0;
//假设买k件物品
long long int Find(long long int k)
{
long long int i,j;
//printf ("购买%lld件物品时:\n",k);
sum = 0;
//将数量为k时每一件物品的价格保存起来再排序
for (i = 1; i <= n; i++)
{
b[i] = a[i] + i * k;
}
sort(b + 1,b + n + 1);
//选择数量为k时价格最小的k件物品购买
for (i = 1; i <= k; i++)
{
//printf ("%lld\n",i);
sum += b[i];
//printf ("够买第%lld件物品已经花费%lld元\n",i,sum);
//当购买这k件物品时预算不够了,代表不能购买这么多数量的物品,返回0
if(sum > m)
{
return 0;
}
}
//可以购买数量为k的物品,返回1
return 1;
}
int main(void)
{
long long int i,j,low,high,mid,mid1,sum1,sum2 = 0;
scanf ("%lld%lld",&n,&m);
for (i = 1; i <= n; i++)
{
scanf ("%lld",&a[i]);
//printf ("第%lld件物品价格:%lld\n",i,a[i]);
}
low = 0;
high = n;
//在0-n中二分数量
while (low <= high)
{
mid = low + (high - low) / 2;
sum1 = Find(mid);
//如果可以购买mid数量的物品,保存mid和sum,然后从mid+1-n二分答案
if(sum1)
{
sum2 = sum;
mid1 = mid;
low = mid + 1;
//printf ("%lld %lld\n",mid1,sum1);
}
//否则从0-mid-1二分可购买的数量
else
{
//printf ("不能购买%lld件物品\n",mid);
high = mid - 1;
}
}
//输出最终的mid1和sum2
printf ("%lld %lld\n",mid1,sum2);
return 0;
}
//心得:当涉及到最大或者最小的问题时,我们都应该联想到二分,二分这个算法真的是非常实用的一个算法,在刷二分题目的过程中我也确实对二分有了更加深入的理解。