1. 程式人生 > >Gadgets for dollars and pounds【CodeForces 609D】【二分答案+貪心】

Gadgets for dollars and pounds【CodeForces 609D】【二分答案+貪心】

題目連結


  還是可以的一道題,但是多次寫飆……也是醉了,題意就是給你N天,每天都有一個相對應的美元以及英鎊的匯率,就是每單位錢需要多少盧比。然後,還有M個物品,他們有相應的價值:第一個數表示,它支援美元支付還是英鎊支付——“1”代表美元、“2”代表英鎊,然後是所需的對應貨幣的數量。我們要K個這樣的物品,並且,我們有S個盧比(初始的時候),然後,我們可以用盧比去換錢,問:最早第幾天的時候,我們可以拿齊K中物品。

  那麼,我們可以二分答案,去假設第幾天的時候會拿到K個物品,然後處理一下字首最小值的貨幣匯率,因為我們可以最後一天再買所有的物品,之前只用囤錢就行了,所以,每個物品的哪天買的時間,可以都為期限時間(SPJ)。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include<time.h>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define son1 (j-1)>0? ans[i-1][j-1] : 0
#define son2 (j+1)<=M? ans[i-1][j+1] : 0
#define son3 (i-2)>0? ans[i-2][j] : 0
#define copppy(pr, ans) memcpy(pr, ans, sizeof(ans))
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, M, K, need_D, need_P;   //Amer、US分別記錄美元、英鎊的字首最小值,就是可以換錢的最小值,need_D和need_P分別記錄需要美元和英鎊的物品的數量
ll Amer[maxN], US[maxN], S;
pair<ll, int> vD[maxN], vP[maxN];
int day_D[maxN], day_P[maxN];   //改天對應的最優貨幣解
int used_D, used_P, ans_D, ans_P;
void init()
{
    Amer[0] = US[0] = Amer[N+1] = US[N+1] = INF;
    need_D = need_P = ans_D = ans_P = 0;
}
bool solve(int day)
{
    ll sum = 0;
    ll dollar = Amer[day], pound = US[day];
    int kk = min(K, need_D);    //用kk記錄下使用美元的最大數量
    used_D = kk;
    for(int i=1; i<=kk; i++)
    {
        sum += dollar * vD[i].first;
    }
    int tot = K - kk;
    used_P = tot;
    for(int i=1; i<=tot; i++)
    {
        sum += pound * vP[i].first;
    }
    int pp = min(K, need_P);
    for(int i=tot+1; i<=pp; i++)
    {
        if(sum <= S) { ans_D = used_D; ans_P = used_P; return true; }
        if(kk == 0) break;
        sum += pound * vP[i].first;
        sum -= dollar * vD[kk--].first;
        used_P++;
        used_D--;
    }
    if(sum <= S) { ans_D = used_D; ans_P = used_P; return true; }
    return false;
}
void Print(int day)
{
    if(day <= 0) return;
    for(int i=1; i<=ans_D; i++) printf("%d %d\n", vD[i].second, day_D[day]);
    for(int i=1; i<=ans_P; i++) printf("%d %d\n", vP[i].second, day_P[day]);
}
int main()
{
    while(scanf("%d%d%d%lld", &N, &M, &K, &S)!=EOF)
    {
        init();
        for(int i=1; i<=N; i++)
        {
            ll e1; scanf("%lld", &e1);
            if(e1 < Amer[i-1])
            {
                day_D[i] = i;
                Amer[i] = e1;
            }
            else
            {
                day_D[i] = day_D[i-1];
                Amer[i] = Amer[i-1];
            }
        }
        for(int i=1; i<=N; i++)
        {
            ll e1; scanf("%lld", &e1);
            if(e1 < US[i-1])
            {
                day_P[i] = i;
                US[i] = e1;
            }
            else
            {
                day_P[i] = day_P[i-1];
                US[i] = US[i-1];
            }
        }
        for(int i=1; i<=M; i++)
        {
            int op; scanf("%d", &op);
            if(op == 1)
            {
                scanf("%lld", &vD[++need_D].first);
                vD[need_D].second = i;
            }
            else
            {
                scanf("%lld", &vP[++need_P].first);
                vP[need_P].second = i;
            }
        }
        sort(vD + 1, vD + 1 + need_D);
        sort(vP + 1, vP + 1 + need_P);
        int L = 1, R = N, ans = -1, mid = 0;
        while(L <= R)
        {
            mid = (L + R)/2;
            if(solve(mid)) { R = mid - 1; ans = mid; }
            else L = mid + 1;
        }
        if(ans == 0) ans = -1;
        printf("%d\n", ans);
        Print(ans);
    }
    return 0;
}
/*
10 10 10 1000000
836 842 645 671 499 554 462 288 89 104
880 722 623 651 591 573 154 532 136 59
1 47
1 169
2 486
1 262
2 752
2 498
2 863
2 616
1 791
1 656
 Answer:
 9
 1 9
 2 9
 4 9
 10 9
 9 9
 3 9
 6 9
 8 9
 5 9
 7 9
*/