18.2.27USACO逃离铜组

写在前面

高一下学期开始了。
第一天来到机房就开始了USACO铜组逃亡。。。
我还是很弱,铜组题也不能在规定时间内打完,还是开了个小号,听了第二题,才晋级的银组。。

T1

题面

Farmer John最讨厌的农活是运输牛粪。为了精简这个过程,他制造了一个伟大的发明:便便传送门!与使用拖拉机拖着装满牛粪的大车从一个地点到另一个地点相比,他可以使用便便传送门将牛粪从一个地点瞬间传送到另一个地点。

Farmer John的农场沿着一条长直道路而建,所以他农场上的每个地点都可以简单地用该地点在道路上的位置来表示(相当于数轴上的一个点)。一个传送门可以用两个数x和y表示,被拖到地点x的牛粪可以瞬间传送到地点y,反之亦然。

Farmer John想要将牛粪从地点a运输到地点b,他建造了一个可能对这一过程有所帮助的传送门(当然,如果没有帮助,他也可以不用)。请帮助他求出他需要使用拖拉机运输牛粪的总距离的最小值。

输入格式(文件名:teleport.in):
输入仅包含一行,为四个用空格分隔的整数:a和b,表示起始地点和结束地点,后面是x和y,表示传送门。所有的位置都是范围为0…100的整数,不一定各不相同。

输出格式(文件名:teleport.out):
输出一个整数,为Farmer John需要用拖拉机运输牛粪的最小距离。

输入样例: 输出样例:
3 10 8 2 3

在这个样例中,最佳策略是将牛粪从位置3运到位置2,传送到位置8,再运到位置10。 所以需要用拖拉机的总距离为1 + 2 = 3。

描述

仅一个传送门,能双向的从一个地方传到另一个地方,求a到b的最短路程。
只有一个传送门,只要考虑是否使用他就行了,若使用,就用a与最左端距离加上b与最右端距离,若不用,则直接a到b的距离。
比较水。

题解

#include<bits/stdc++.h>
using namespace std;
int s,e,x,y,ans;
int main()
{
    freopen("teleport.in","r",stdin);
    freopen("teleport.out","w",stdout);
    scanf("%d%d%d%d",&s,&e,&x,&y);
    if (x>y) swap(x,y);
    if (s>e) swap(s,e);
    ans=min(abs(x-s)+abs(y-e),e-s);
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2

题面

为了准备即将到来的蹄球锦标赛,Farmer John正在训练他的N头奶牛(方便起见,编号为1…N,其中1≤N≤100)进行传球。这些奶牛在牛棚一侧沿直线排列,第ii号奶牛位于距离牛棚xi的地方(1≤xi≤1000)。每头奶牛都在不同的位置上。
在训练开始的时候,Farmer John会将若干个球传给不同的奶牛。当第i号奶牛接到球时,无论是从Farmer John或是从另一头奶牛传来的,她会将球传给最近的奶牛(如果有多头奶牛与她距离相同,她会传给其中距左边最远的那头奶牛)。为了使所有奶牛都有机会练习到传球,Farmer John想要确保每头奶牛都持球至少一次。帮助他求出为了达到这一目的他开始时至少要传出的球的数量。假设他在开始的时候能将球传给最适当的一组奶牛。

输入格式(文件名:hoofball.in):

输入的第一行包含N。第二行包含N个用空格分隔的整数,其中第i个整数为xi。
输出格式(文件名:hoofball.out):

输出Farmer John开始的时候最少需要传出的球的数量,使得所有奶牛至少持球一次。
输入样例:

5
7 1 3 11 4
输出样例:

2
在上面的样例中,Farmer John应该将球传给位于x=1的奶牛和位于x=11的奶牛。位于x=1的奶牛会将她的球传给位于x=3的奶牛,在此之后这个球会在位于x=3的奶牛和位于x=4的奶牛之间来回传递。位于x=11的奶牛会将她的球传给位于x=7的奶牛,然后球会被传给位于x=4的奶牛,在此之后这个球也会在位于x=3的奶牛和位于x=4的奶牛之间来回传递。这样的话,所有的奶牛都会至少一次接到球(可能从Farmer John,也可能从另一头奶牛)。

可以看出,不存在这样一头奶牛,Farmer John可以将球传给她之后所有奶牛最终都能被传到球。

描述

牛会传球,不断传来传去传给离自己最近的牛(若同样近给左边)。。。求需要几个球,能使所有牛都能参加游戏。
这题坑了我好久。。。
本来想着上升下降序列统计。
但怎么也过不去。。。
听了sj大佬的方法,我家的猫说:“miaoa”。
就是这图中肯定有环。而且环一定存在于相邻两个点。而且不可能有两个环相连,也就是一个强联通分量中只有一个环。
那么不管左边或右边向此环有多少个成链的点指向,都只需要一个球。
,而若两边都有指向此环,则需两球。

如图
这里写图片描述
记录每个点传球方向。再进行判断,就可以ac啦!!!

题解

#include<bits/stdc++.h>
using namespace std;
int n,ans=0;
int a[110]={};
int sum[110]={};
int lr[110]={};
int main()
{
    freopen("hoofball.in","r",stdin);
    freopen("hoofball.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<n;i++)
      sum[i]=a[i+1]-a[i];
    lr[1]=-1;
    lr[n]=1;
    for(int i=1;i<n-1;i++)
      if (sum[i]>sum[i+1]) 
        lr[i+1]=-1;
      else lr[i+1]=1;
    for(int i=1;i<n;i++)
      {
        if (lr[i]==-1&&lr[i+1]==1) 
          {
            ans++;
            if (lr[i-1]==-1&&lr[i+2]==1) ans++;
          }
      }  
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T3

题面

一大清早,Farmer John就被木材破裂的声音吵醒了。是这些奶牛们干的,她们又逃出牛棚了!
Farmer John已经厌烦了奶牛在清晨出逃,他觉得受够了:是时候采取强硬措施了。他在牛棚的墙上钉了一个计数器,追踪从上次出逃开始经过的天数。所以如果某一天早上发生了出逃事件,这一天的计数器就为0;如果最近的出逃是3天前,计数器读数就为3。Farmer John一丝不苟地记录了每一天计数器的读数。

年末到了,Farmer John准备做一些统计。他说,你们这些奶牛会付出代价的!然而意想不到的是,他的记录的一些条目竟然丢失了!

Farmer John确信他是在发生出逃的某一天开始记录的。请帮助他确定,在所有与残留记录条目一致的事件序列中,基于记录的时间,最少和最多可能发生的出逃次数。

输入格式(文件名:taming.in):

输入的第一行包含一个整数NN(1≤N≤100),表示从Farmer John开始对奶牛出逃计数器进行计数以来已经经过的天数。
第二行包含N个空格分隔的整数。第i个整数是−1,表示第ii天的记录丢失了,或者是一个非负整数ai(不超过100),表示在第i天计数器的数字是ai。

输出格式(文件名:taming.out):

如果没有事件序列与Farmer John的残留记录以及他所确定的奶牛在第11天清晨出逃这一事实相一致,输出一个整数−1。否则,输出两个空格分隔的整数m和M,其中m为所有事件序列中出逃的最少次数,M为最多次数。
输入样例:

4
-1 -1 -1 1
输出样例:

2 3
在这个样例中,我们可以推断第3天必然有出逃发生。我们已经知道在第1天也发生了出逃,所以最后不确定的只有第2天是否发生了出逃。因此,总共发生了2至3次出逃。

描述

残缺的记录,记录了几天前有奶牛逃亡事件。
求发生逃亡事件可能最少数和可能最多数。
由于第一天一定有逃亡事件发生,那么一定是0;
然后后面每出现一个非-1数,就可以提供给我们两个信息。
1.ai天前确定发生了一个事件。
2.这ai天都没发生事件,否则计数器会刷新。
那么每获得一个非-1数,则可以更新summin;
最后得出没被确定的天数,加上summin就是所求summax;
还需要很多细节,特判等。。。
比如不符合逻辑时输出-1;

题解

#include<bits/stdc++.h>
using namespace std;
int n,summin=0,summax;
int a[110]={};
bool f[110]={};
int main()
{
    freopen("taming.in","r",stdin);
    freopen("taming.out","w",stdout);
    scanf("%d",&n);
    bool p=false;
    for(int i=1;i<=n;i++)
      {
        scanf("%d",&a[i]);
        if (a[i]!=-1) p=true;
      }
    if (!p)
      {
        printf("%d %d",1,n);
        fclose(stdin);
        fclose(stdout);
        return 0;
      }
    for(int i=n;i>=1;i--)
      {
        if (a[i]!=-1&&f[i]==0)
          {
            for(int j=i;j>=i-a[i];j--)
              {
                f[j]=1;
                if (a[j]!=-1&&a[j]!=a[i]-i+j||a[i]>=i)
                  {
                    cout<<-1;
                    fclose(stdin);
                    fclose(stdout);
                    return 0;
                  }
              }
            summin++;
          }
      }
    if (f[1]==0) summin++;
    for(int i=2;i<=n;i++)
      if (f[i]==0) summax++;
    printf("%d %d",summin,summin+summax);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

总结

不能小看USACO的题目。
还是要多思考。
寒假结束了,把心收回来。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值