CodeForces 609D Gadgets for dollars and pounds

题意:

有n天,m个工具,至少买k个工具,有s元。第二行第三行是 第一种 硬币 和第二种硬币的汇率。询问最少多少天可以买完。

思路:

二分查找答案,如果可以就左移,否则右移。在查找时,要查询的是在1-》x天内最小的汇率。可以直接排序,nlog,我用的是线段树,logn,感觉好傻。。复杂度分析没注意。。因为会TLE。找到最小汇率,取前k小的工具判断就好了


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <vector>
using namespace std;

typedef long long ll;
const int maxn=200005;
struct node
{
    ll left,right;
    ll minn;
}treea[4*maxn],treeb[maxn*4];

ll a[maxn];
ll b[maxn];
ll num[maxn];
ll inf=0x3f3f3f3f;
struct tp
{
    int id;
    ll price;
}gooda[maxn],goodb[maxn];

int cnta=0,cntb=0;
void builda(int i,int left,int right)
{
    treea[i].left=left,treea[i].right=right;
    treea[i].minn=inf;
    if(left==right)
    {
        treea[i].minn=a[left];
        return ;
    }
    int mid=(treea[i].left+treea[i].right)>>1;
    builda(i<<1,left,mid);
    builda(i<<1|1,mid+1,right);
    treea[i].minn=min(treea[i<<1].minn,treea[i<<1|1].minn);
    return ;
}
void buildb(int i,int left,int right)
{
    treeb[i].left=left,treeb[i].right=right;
    treeb[i].minn=inf;
    if(left==right)
    {
        treeb[i].minn=b[left];
        return ;
    }
    int mid=(treeb[i].left+treeb[i].right)>>1;
    buildb(i<<1,left,mid);
    buildb(i<<1|1,mid+1,right);
    treeb[i].minn=min(treeb[i<<1].minn,treeb[i<<1|1].minn);
    return ;
}
int querya(int i,int left,int right)
{
    if(treea[i].left==left&&treea[i].right==right)
    {
        return treea[i].minn;
    }
    int mid=(treea[i].left+treea[i].right)>>1;
    if(right<=mid)
    {
        return querya(i<<1,left,right);
    }
    else if(left>mid)
    {
        return querya(i<<1|1,left,right);
    }
    else
    {
        return min(querya(i<<1,left,mid),querya(i<<1|1,mid+1,right));
    }
}

int queryb(int i,int left,int right)
{
    if(treeb[i].left==left&&treeb[i].right==right)
    {
        return treeb[i].minn;
    }
    int mid=(treeb[i].left+treeb[i].right)>>1;
    if(right<=mid)
    {
        return queryb(i<<1,left,right);
    }
    else if(left>mid)
    {
        return queryb(i<<1|1,left,right);
    }
    else
    {
        return min(queryb(i<<1,left,mid),queryb(i<<1|1,mid+1,right));
    }
}

bool judge(int x,ll mon,int k)
{

    ll ma=querya(1,1,x);
    ll mb=queryb(1,1,x);
    long long res=0;
    int num=0;
    int flaga=0,flagb=0;
    while(num++<k)
    {
        int op=0;
        ll tmp=inf;
        if(flaga+1<=cnta)
        {
            tmp=gooda[flaga+1].price*ma;
            op=1;
        }
        if(flagb+1<=cntb)
        {
            if(tmp>goodb[flagb+1].price*mb)
            {
                op=2;
                tmp=goodb[flagb+1].price*mb;
            }
        }
        if(op==0)
           return false;
        if(op==1) flaga++;
        else flagb++;
        res+=tmp;
        if(res>mon)
            return false;
    }
    return true;

}
int cmp(tp x,tp y)
{
    return x.price<y.price;
}
int main()
{
    ll n,m,k,s;
    scanf("%lld%lld%lld%lld",&n,&m,&k,&s);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;i++)
        scanf("%lld",&b[i]);
    for(int i=1;i<=m;i++)
    {
        int t;
        scanf("%d",&t);
        if(t==1)
        {
            scanf("%lld",&gooda[++cnta].price);
            gooda[cnta].id=i;
        }
        else
        {
            scanf("%lld",&goodb[++cntb].price);
            goodb[cntb].id=i;
        }
    }
    sort(gooda+1,gooda+1+cnta,cmp);
    sort(goodb+1,goodb+1+cntb,cmp);
    builda(1,1,n);
    buildb(1,1,n);
    int ans=-1;
    int l=1,r=n;
    int mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(judge(mid,s,k))
        {
            ans=mid;
            r=mid-1;
        }
        else
        {
            l=mid+1;
        }
    }
    if(ans==-1)
        printf("-1\n");
    else
    {
        printf("%d\n",ans);
        int ansa=0,ansb=0;
        ll ma=querya(1,1,ans);
        ll mb=queryb(1,1,ans);
        for(int i=1;i<=ans;i++)
        {
            if(a[i]==ma)
                ansa=i;
            if(b[i]==mb)
                ansb=i;
        }
        int num=0;
        int flaga=0,flagb=0;
        while(num++<k)
        {
            int op=0;
            ll tmp=inf;
            if(flaga+1<=cnta)
            {
                op=1;
                tmp=ma*gooda[flaga+1].price;
            }
            if(flagb+1<=cntb)
            {
                if(tmp>mb*goodb[flagb+1].price)
                {
                    op=2;
                }
            }
            if(op==1)
            {
                printf("%d %d",gooda[flaga+1].id,ansa);
                flaga++;
            }
            else
            {

                printf("%d %d",goodb[flagb+1].id,ansb);
                flagb++;
            }
            printf("\n");
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值