2018.8.7提高B组模拟考试

T1 题意简述:jzoj5461

 

Description

X 城的商场中,有着琳琅满目的各种商品。一日,小X 带着小Y 前来购物,小Y 一共看中了n件商品,每一件商品价格为Pi。小X 现在手中共有m个单位的现金,以及k 张优惠券。小X 可以在购买某件商品时,使用至多一张优惠券,若如此做,该商品的价格会下降至Qi。
小X 希望尽可能多地满足小Y 的愿望,所以小X 想要知道他至多能购买多少件商品。

Input

第一行包含三个整数n,k,m,表示商品总数,小X 拥有的优惠券与现金总数。
接下来n行每行包含两个整数Pi,Qi。

Output

共一行包含一个整数,表示小X 至多能购买的物品数。

Data Constraint

 
 

   解题思路:贪心。

             考虑先用完k张优惠券,只需将商品按优惠价排序,依次判断钱是否足够,若是则ans++,否

             则直接退出循环并输出ans即可。

             k张优惠券用完后若钱还未用完,则考虑用前面商品的优惠券买后面的商品。注意要把未买

             的商品按原价重新排序。只需把用了优惠券的商品的原价与优惠价之差价放进一个小根堆,

             每次判断:此商品原价是否小于堆顶商品差价+此商品优惠价。若是则直接用原价买即可,

             否则用堆顶商品差价+此商品优惠价买即可。

             注意有0张优惠券的情况,因此要特判队列是否为空,若是则直接用原价买即可。

             由于本蒟蒻及ErkkiErkko均认为把商品按原价重新排序的方法有误,故欢迎大佬Hack。

             8.11 fix:

             Zinn大佬已Hack掉以上算法。具体数据请看讨论。

             附上sdfzsyq大佬的正确代码:

             https://blog.csdn.net/qq_40448823/article/details/81488195

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
ll n,k,m,ans;
priority_queue<ll,vector<ll>,greater<ll> > que;
struct uio{
    ll val,fre;
}war[50001];
bool cmp(uio x,uio y)
{
    if(x.fre==y.fre)
        return x.val<y.val;
    return x.fre<y.fre;
}
bool cmp1(uio x,uio y)
{
    return x.val<y.val;
}
int main()
{
    freopen("shopping.in","r",stdin);
    freopen("shopping.out","w",stdout);
    scanf("%lld%lld%lld",&n,&k,&m);
    for(ll i=1;i<=n;i++)
        scanf("%lld%lld",&war[i].val,&war[i].fre);
    sort(war+1,war+1+n,cmp);
    for(ll i=1;i<=k;i++)
    {
        que.push(war[i].val-war[i].fre);
        if(m>=war[i].fre) m-=war[i].fre,ans++;
    }
    sort(war+1+k,war+1+n,cmp1);
    for(ll i=k+1;i<=n;i++)
    {
        if(m>=war[i].val&&(que.empty()||que.top()>war[i].val-war[i].fre)) m-=war[i].val,ans++;
        else if(!que.empty()&&m>=war[i].fre+que.top()) m-=war[i].fre+que.top(),ans++,que.pop(),que.push(war[i].val-war[i].fre);
    }
    printf("%lld\n",ans);
    return 0;
}

 


 

T2 题意简述:jzoj5455

 

Description

企鹅国的网吧们之间由网线互相连接,形成一棵树的结构。现在由于冬天到了,供暖部门缺少燃料,于是他们决定去拆一些网线来做燃料。但是现在有K只企鹅要上网和别人联机游戏,所以他们需要把这K只企鹅安排到不同的机房(两只企鹅在同一个机房会吵架),然后拆掉一些网线,但是需要保证每只企鹅至少还能通过留下来的网线和至少另一只企鹅联机游戏。
所以他们想知道,最少需要保留多少根网线?

Input

第一行一个整数T,表示数据组数;
每组数据第一行两个整数N,K,表示总共的机房数目和企鹅数目。
第二行N-1个整数,第i个整数Ai表示机房i+1和机房Ai有一根网线连接(1≤Ai≤i)。

Output

每组数据输出一个整数表示最少保留的网线数目。

Data Constraint

对于30%的数据:N≤15;
对于50%的数据:N≤300;
对于70%的数据:N≤2000;
对于100%的数据:2≤K≤N≤100000,T≤10。

 

   解题思路:乍一看是一道树形dp...然而现实狠狠地打了你的脸...

             这道题的难度远不及树形dp...只需要分两步:

             1.计算出有多少对企鹅能只用一根网线相连

             2.若还有企鹅没有连接就每只企鹅分配一根网线

             就完了...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll T,n,m,cnt,dot,line,head[100001],vis[100001];
struct uio{
    ll nxt,to;
}edge[200001];
void add(ll x,ll y)
{
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
void dfs(ll x,ll fa)
{
    for(ll i=head[x];i;i=edge[i].nxt)
    {
        ll y=edge[i].to;
        if(y==fa) continue;
        dfs(y,x);
        if(!vis[x]&&!vis[y])
        {
            vis[x]=vis[y]=1;
            if(dot<m) line++;
            dot+=2;
        }
    }
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%lld",&T);
    while(T--)
    {
        cnt=dot=line=0;
        memset(head,0,sizeof(head));
        memset(vis,0,sizeof(vis));
        scanf("%lld%lld",&n,&m);
        for(ll i=1;i<n;i++)
        {
            ll u;
            scanf("%lld",&u);
            add(u,i+1),add(i+1,u);
        }
        dfs(1,0);
        if(dot>=m) printf("%d\n",line);
        else printf("%d\n",m-line);
    }
    return 0;
}
posted @ 2018-08-07 20:53  radishえらい  阅读(288)  评论(2编辑  收藏  举报