入门赛9

前言

由于题目有点难,历史遗留问题比较严重,所以这篇博客迟了点。

本赛涉及题目:
A: [Snacktower]

B: [The Queue]

C: [Garland]

D: [Cartons of milk]

E: [Change-free]


T1 Snacktower

题面

原题地址: [A]

题意

自己搜吧,真不会讲。

思路

见代码。

代码

#include<bits/stdc++.h>
using namespace std;
int n,i,k,m[100005],x;
int main()
{
    scanf("%d",&n);k=n;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&x);
        m[x]++;
        while(m[k]==1)
        {
            printf("%d ",k);
            k--;
        }
        printf("\n");
    }
    return 0;
}

小结

水题*1。


T2 The Queue

题面

原题地址: [B]

题意

服务站在ts开门,tf关门,受理每一个人需要t分钟。有n个人需要受理,你只能排在与你同时间到达的人后面,问你什么时候到达所需的等待时间最小。

思路

在每个人前面的情况都算一遍,再与在最后到的时间进行比较(如果可以的话)。

代码

#include<bits/stdc++.h>
using namespace std;
long long ts,tf,t,n,a,m=1e12+10,ans;
int main()
{
    scanf("%lld%lld%lld%lld",&ts,&tf,&t,&n);
    while(n--)//暴枚每一个人;
    {
        scanf("%lld",&a);
        if(a&&a<=tf-t)
        {
            if(max(ts,a-1)<=tf-t&&ts-a+1<m) m=ts-a+1,ans=min(a-1,ts);
            ts=max(ts,a)+t;//每个人的最早受理时间;
        }
    }
    if(ts<=tf-t) ans=ts;
    printf("%lld",ans);
    return 0;
}

小结

水题*2。


T3 Garland

题面

原题地址: [C]

题意

有n个灯连成一串,每一个灯都有温度,问能否将这一串灯剪成三段,使每一段的灯的温度总和相等,输出剪的边下面那个点的编号。

思路

先向根维护一个前缀和,如果有总温度的1/3,就将答案+1,并把这个值制成零,如果有不少于两个答案,输出答案,否则输出-1。

代码

#include<bits/stdc++.h>
using namespace std;
struct Line { int point,next; }line[1000005];
int head[1000005],k[1000005],i,ii,n,e,sum,v,j,ans_1,ans_2,ans[5];
void add(int u,int v) { line[e].point=v;line[e].next=head[u];head[u]=e++; }
void dfs(int i)
{
    int p=head[i];
    while(p!=-1) { dfs(line[p].point);k[i]+=k[line[p].point];p=line[p].next; }//往叶子节点搜素;
    if(k[i]==sum&&i!=ii) ans[++ans[0]]=i,k[i]=0;//递归时计算前缀和,由于根节点必为一段的总和,所以要避开根节点。
    if(ans[0]==2) { printf("%d %d",ans[2],ans[1]);exit(0); }//输出答案;
}
int main()
{
    memset(head,-1,sizeof(head));
    for(scanf("%d",&n),i=1;i<=n;i++){ scanf("%d%d",&v,&k[i]);if(v) add(v,i);else ii=i;sum+=k[i]; }
    if(sum%3) printf("-1");else { sum/=3;dfs(ii);if(ans[0]!=2) printf("-1"); }
    return 0;
}

小结

应为刚开始懒,不想建树,然后就GG了。


T4 Cartons of milk

题面

原题地址: [D]

题意

家里有n瓶牛奶,商店里有m瓶牛奶,每瓶牛奶都有保质期,保质期过来就要扔掉,每天能喝t瓶牛奶,在不扔掉任何牛奶的情况下,最多能在商店买多少瓶牛奶,输出牛奶编号。

思路

网上都说是要二分答案,时间复杂度O(n log n),但时间长还难打,然后我想出了一个O(n)的代码(sort改桶排就是O(n)了),如下:
先判家里的牛奶,再将商店里的牛奶带编号排序,保质期靠后的牛奶要先买,因为允许喝的天数会多一点
预处理每天最大喝牛奶的量,将家里的牛奶桶排加前缀和,两者比较,如果家里的较多,则输出-1。
然后处理出每天还可以喝多少瓶牛奶,由于是前缀和,前面的答案会使后面的所有的值-1,所以要传一个minn回来。

代码

#include<bits/stdc++.h>
using namespace std;
struct Milk { long long time,num; }milk[1000005];
long long n,m,k,i,m1[10000005],ans[1000005],minn,x,p;
bool cmp(Milk x,Milk y) { return x.time>y.time; }
int main()
{
    for(scanf("%lld%lld%lld",&n,&m,&k),i=1;i<=n;i++) scanf("%lld",&x),m1[x]++;
    for(i=0;i<=10000002;i++)
    {
        if(i) m1[i]+=m1[i-1];
        if(m1[i]>(i+1)*k&&i<=n)
        {
            printf("-1");
            return 0;
        }
    }
    for(i=0;i<=10000002;i++) m1[i]=(i+1)*k-m1[i];
    for(i=1;i<=m;i++) scanf("%lld",&milk[i].time),milk[i].num=i;
    sort(milk+1,milk+m+1,cmp);minn=m1[milk[1].time];
    for(i=1;i<=m&&minn;i++) if(minn&&m1[milk[i].time]) ans[++p]=milk[i].num,minn=min(--minn,--m1[milk[i].time]);
    sort(ans+1,ans+p+1);
    for(printf("%lld\n",p),i=1;i<=p;i++) printf("%lld ",ans[i]);
    return 0;
}

小结

二分不会写,为什么这个我会写?


T5 Change-free

题面

原题地址: [E]

题意

你有无限的纸币和m个硬币,每天你要买一个东西,如果你让售货员找钱,他的不开心值会上升,然后你会获得硬币,求最小不开心总值。

思路

优先队列加模拟(不开心值小的先出)。

代码 priority_queue

#include<bits/stdc++.h>
#define N 100000
#define ii pair<long,long long>
using namespace std;
priority_queue<ii,vector<ii>,greater<ii> > pq;
long long ans,i,n,m,x,note[N+5],coin[N+5];
int main()
{
    for(scanf("%lld%d",&n,&m),i=1;i<=n;i++) scanf("%lld",&coin[i]),note[i]=coin[i]/100,coin[i]%=100;
    for(i=1;i<=n;i++)
    {
        m-=coin[i];scanf("%lld",&x);
        if(coin[i]) pq.push(ii(x*(100-coin[i]),i));
        if(m<0)
        {
            m+=100;ans+=pq.top().first;
            note[pq.top().second]++;
            coin[pq.top().second]=0;
            pq.pop();
        }
    }
    for(printf("%lld\n",ans),i=1;i<=n;i++) printf("%lld %lld\n",note[i],coin[i]); 
    return 0;
}

代码 set

#include<bits/stdc++.h>
#define ii pair<long,long>
#define N 100000
using namespace std;
set<ii> s;long long n,m,x,i,note[N+5],coin[N+5],ans;
int main()
{
    for(scanf("%lld%lld",&n,&m),i=1;i<=n;i++) scanf("%lld",&coin[i]),note[i]=coin[i]/100,coin[i]%=100;
    for(i=1;i<=n;i++)
    {
        m-=coin[i];scanf("%lld",&x);
        if(coin[i]) s.insert(ii(x*(100-coin[i]),i));
        if(m<0)
        {
            m+=100;ans+=s.begin()->first;
            note[s.begin()->second]++;
            coin[s.begin()->second]=0;
            s.erase(s.begin()); 
        }
    }
    for(printf("%lld\n",ans),i=1;i<=n;i++) printf("%lld %lld\n",note[i],coin[i]);
    return 0;
}

小结

水题*5。


总结

比赛时不会打,比赛后随便打。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值