题目链接:http://codeforces.com/problemset/problem/609/D
题意:一个人手上有s卢布,他要在n天内买m样东西中的k样样例第二行是多少卢布换一美刀,第三行是多少卢布换一英镑然后接下来是m样东西,告诉你每样东西用什么货币结账(1是美刀,2是卢布),以及要多少那种外币要求:最早完成买k样的天数,以及输出方案输出第几天买完k样商品,然后k行购买的商品的id,第几天购买的输出任意答案就可以了 一种商品只能购买一次,但是一天可以买多种商品
思路:对于前i天购买东西,肯定是选择汇率最高的时候购买。对于某一天,我们能用O(n)的复杂度来求出当前最低所需要的钱来买k件商品,这里面只要把商品按照购买方式分类,然后排序一遍,之后就很好维护了。对于前i天先求出前i天里面两种汇率最大的分别是哪两天,预处理一下,之后只要二分i,就能得到答案了
代码:
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
typedef long long ll;
const int maxn = 2e5+5;
int n, m, k, s;
pii s1[maxn], s2[maxn];
vector<pii> a1, a2;
bool check(int x, bool print = false)
{
int l = k - min(k, (int)a2.size());
int r = min(k, (int)a1.size()), pos = -1;
ll a = s1[x].first, b = s2[x].first;
ll sum = 0;
for(int i = 1; i <= l; i++)
sum += a * a1[i-1].first;
for(int i = 1; i <= k - l; i++)
sum += b * a2[i-1].first;
for(int i = l; i <= r; i++)
{
if(sum <= s)
{
pos = i;
break;
}
if(l == r)
break;
sum += a * a1[i].first;
sum -= b * a2[k-i-1].first;
}
if(pos == -1)
return false;
if(!print)
return true;
printf("%d\n", x);
for(int i = 1; i <= pos; i++)
printf("%d %d\n", a1[i-1].second, s1[x].second);
for(int i = 1; i <= k - pos; i++)
printf("%d %d\n", a2[i-1].second, s2[x].second);
return true;
}
void solve()
{
int l = 1, r = n, mid;
if(!check(r))
{
puts("-1");
return ;
}
while(l <= r)
{
mid = (l + r) >> 1;
if(check(mid))
r = mid - 1;
else
l = mid + 1;
}
check(r + 1, true);
}
int main()
{
while(scanf("%d%d%d%d", &n, &m, &k, &s) != EOF)
{
a1.clear();
a2.clear();
pii temp;
s1[0] = s2[0] = pii(0x3f3f3f3f, 0x3f3f3f3f);
for(int i = 1; i <= n; i++)
{
temp.second = i;
scanf("%d", &temp.first);
s1[i] = min(s1[i-1], temp);
}
for(int i = 1; i <= n; i++)
{
temp.second = i;
scanf("%d", &temp.first);
s2[i] = min(s2[i-1], temp);
}
for(int i = 1; i <= m; i++)
{
int id;
temp.second = i;
scanf("%d%d", &id, &temp.first);
if(id == 1)
a1.push_back(temp);
else
a2.push_back(temp);
}
sort(a1.begin(), a1.end());
sort(a2.begin(), a2.end());
solve();
}
return 0;
}