【题解】USACO 2020 OPEN Sliver(银组)

2024-02-03 05:10

本文主要是介绍【题解】USACO 2020 OPEN Sliver(银组),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Social Distancing

题面

题目描述
由于高传染性的牛传染病 COWVID-19 的爆发,Farmer John 非常担忧他的奶牛们的健康。
为了限制疾病的传播,Farmer John 的 N 头奶牛 ( 2 ≤ N ≤ 1 0 5 ) (2≤N≤10^5) 2N105决定践行“社交距离”,分散到农场的各处。农场的形状如一维数轴,上有 M 个互不相交的区间 ( 1 ≤ M ≤ 1 0 5 ) (1≤M≤10^5) 1M105,其中有可用来放牧的青草。奶牛们想要使她们位于不同的整数位置,每个位置上均有草,并且最大化 D 的值,其中 D 为最近的两头奶牛之间的距离。请帮助奶牛们求出 D 的最大可能值。
输入格式(文件名:socdist.in):
输入的第一行包含 N 和 M。以下 M 行每行用两个整数 a 和 b 描述一个区间,其中 0 ≤ a ≤ b ≤ 1 0 18 0≤a≤b≤10^{18} 0ab1018。没有两个区间有重合部分或在端点处相交。位于一个区间的端点上的奶牛视为在草上。
输出格式(文件名:socdist.out):
输出 D 的最大可能值,使得所有奶牛之间的距离均不小于 D 单位。保证存在 D>0 的解。
输入样例:

5 3
0 2
4 7
9 9

输出样例:

2

样例解释
取到 D=2 的一种方式是令奶牛们处在位置 0、2、4、6 和 9。
测试点性质:
测试点 2-3 满足 b ≤ 1 0 5 b≤10^5 b105
测试点 4-10 没有额外限制。

算法分析

标准的二分答案。二分奶牛之间的距离D。

参考程序


Cereal

题面

题目描述

Farmer John 的奶牛们的早餐最爱当然是麦片了!事实上,奶牛们的胃口是如此之大,每头奶牛一顿饭可以吃掉整整一箱麦片。
最近农场收到了一份快递,内有 M M M 种不同种类的麦片( 1 ≤ M ≤ 1 0 5 1≤M≤10^5 1M105)。不幸的是,每种麦片只有一箱! N N N 头奶牛( 1 ≤ N ≤ 1 0 5 1≤N≤10^5 1N105)中的每头都有她最爱的麦片和第二喜爱的麦片。给定一些可选的麦片,奶牛会执行如下的过程:

如果她最爱的麦片还在,取走并离开。
否则,如果她第二喜爱的麦片还在,取走并离开。
否则,她会失望地哞叫一声然后不带走一片麦片地离开。
奶牛们排队领取麦片。对于每一个 0 ≤ i ≤ N − 1 0≤i≤N−1 0iN1,求如果 Farmer John 从队伍中移除前 i i i 头奶牛,有多少奶牛会取走一箱麦片。

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

输入的第一行包含两个空格分隔的整数 N N N M M M
对于每一个 1 ≤ i ≤ N 1≤i≤N 1iN,第 i i i 行包含两个空格分隔的整数 f i f_i fi s i s_i si 1 ≤ f i , s i ≤ M , 且 f i ≠ s i ) 1≤f_i,s_i≤M,且 f_i≠s_i) 1fi,siMfi=si,为队伍中第 i i i 头奶牛最喜爱和第二喜爱的麦片。

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

对于每一个 0 ≤ i ≤ N − 1 0≤i≤N−1 0iN1,输出一行,包含对于 i i i 的答案。

输入样例:

4 2
1 2
1 2
1 2
1 2

输出样例:

2
2
2
1

如果至少两头奶牛留下,那么恰有两头奶牛取走了一箱麦片。

测试点性质:

测试点 2-3 满足 N,M≤1000。

测试点 4-10 没有额外限制。

算法分析

模拟。
如果依次模拟删除前 0 0 0头牛,前 1 1 1头牛,…
如果删除第 i i i头牛,那么第 i i i头牛选的麦片有可能被第 j j j头牛选,第 j j j头牛选的麦片有可能被第 k k k头牛选…
当删除第 i i i头牛,麦片的选择会产生连锁反应,有可能所有的奶牛的选择都会被打乱。
在这里我们逆序考虑。
逆序考虑,先考虑删除前 N − 1 N-1 N1头牛,前 N − 2 N-2 N2头牛,…前 0 0 0头牛
考虑第 i i i头牛,第 i + 1 i+1 i+1~ N N N头牛已经选择。如果第 i i i头牛第一喜欢的还在,那么直接选择,如果被第 j ( j > i ) j(j>i) j(j>i)头牛选了,那么抢过来( i i i排在前面有优先权),如果第 j j j头牛被抢的是第一喜欢的就考虑第二喜欢的,否则就不选。
每头牛只会有三种选择,不会存在连锁反应。总的时间复杂度为 O ( N 2 ) O(N_2) O(N2)

参考程序
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
int n,m,f[N],s[N];
int cnt,ans[N],vis[N];  //标记
void dfs(int k,int x)
{if(!vis[x]) {vis[x]=k;cnt++;return;}else if(vis[x]>k)    //被后面的奶牛选了 {int t=vis[x];vis[x]=k;       //把后面奶牛选的抢了(前面的奶牛先选) if(f[t]==x) dfs(t,s[t]);    //后面的奶牛选第二喜欢的,否则就没得 }
} 
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d%d",&f[i],&s[i]);for(int i=n;i>=1;i--){dfs(i,f[i]);        //选最喜欢的 ans[i-1]=cnt;   } for(int i=0;i<n;i++)printf("%d\n",ans[i]); return 0;   
} 

The Moo Particle

题目描述
在 COWVID-19 爆发期间 Farmer John 的奶牛们为了安全进行了隔离,她们想到了一种全新的方式缓解无聊:研究高等物理!事实上,她们甚至成功发现了一种新的亚原子粒子,她们将其命名为“哞粒子”。
奶牛们正在进行一项有关 N N N 个哞粒子的实验( 1 ≤ N ≤ 1 0 5 1≤N≤10^5 1N105)。粒子 i i i 的“自旋”可以用范围在 − 1 0 9 −10^9 109 1 0 9 10^9 109 之间的两个整数 x i x_i xi y i y_i yi 来描述。有时两个哞粒子会发生相互作用。自旋为 ( x i , y i x_i,y_i xi,yi) 和 ( x j , y j x_j,y_j xj,yj) 的两个粒子之间仅当 x i ≤ x j x_i≤x_j xixj 并且 y i ≤ y j y_i≤y_j yiyj 时会发生相互作用。在这些条件下,有可能这两个粒子中的一个会消失(另一个粒子不会发生任何变化)。在任意给定的时刻,至多只有一次相互作用会发生。
奶牛们想要知道在经过一些任意的相互作用之后剩余的哞粒子的最小数量。
输入格式(文件名:moop.in):
输入的第一行包含一个整数 N,为哞粒子的初始数量。以下 N 行每行包含两个空格分隔的整数,为一个粒子的自旋。每个粒子的自旋各不相同。
输出格式(文件名:moop.out):
输出一个整数,为经过一些任意的相互作用之后剩余的哞粒子的最小数量。
输入样例:

4
1 0
0 1
-1 0
0 -1

输出样例:

1

样例解释
一个可能的相互作用顺序:
粒子 1 和 4 相互作用,粒子 1 消失。
粒子 2 和 4 相互作用,粒子 4 消失。
粒子 2 和 3 相互作用,粒子 3 消失。
仅留下粒子 2。
输入样例:

3
0 0
1 1
-1 3

输出样例:

2

样例解释
粒子 3 不能与任何其他两个粒子相互作用,所以它必然会留下。粒子 1 和 2 中必然留下至少一个。
测试点性质:
测试点 3-6 满足 N≤1000。
测试点 7-12 没有额外限制。

算法分析

解法一:并查集
如果用边将能够互相作用的粒子连在一起,那么在同一个连通块中的粒子,可以相互作用,直到只剩下一个粒子,最后的答案就是连通块的数量。可以使用并查集实现,一个连通块就是一个集合,但是时间复杂度为 O ( N 2 ) O(N^2) O(N2),只能得一半的分数。

解法二:
将x从小到大排序,y从小到大排序。
考虑y坐标。
有右侧几个点,前面三个点组成一个集合,考虑第四个点i?
在这里插入图片描述
只要在i之前找到y值比yi小的点或者在i之后找到比yi大的点都能够相互作用
如何在最快的时间找到在i之前比yi小,在i之后比yi大的点?
前缀最小y值,后缀最大y值

参考程序
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
int n;
struct node
{int x,y;
}a[N];
int miny[N],maxy[N];
bool comp(node u,node v)
{if(u.x==v.x)	return u.y<v.y?1:0;else return u.x<v.x?1:0;
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);sort(a+1,a+n+1,comp);	//x,y从小到大排序 miny[1]=a[1].y;for(int i=2;i<=n;i++)	//前缀最小纵坐标yminy[i]=min(miny[i-1],a[i].y);maxy[n]=a[n].y;for(int i=n-1;i>=1;i--)	//后缀最大纵坐标 maxy[i]=max(maxy[i+1],a[i].y); int ans=1;for(int i=1;i<=n;i++)if(miny[i]>maxy[i+1])	ans++;	//当miny[i]<=maxy[i+1]时,当前点i肯定可以和最小的y或者最大的y组成一组(x已经从小到大排序了) ,否则单独成一个集合cout<<ans<<endl; return 0;
}

这篇关于【题解】USACO 2020 OPEN Sliver(银组)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/673074

相关文章

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

usaco 1.3 Calf Flac(暴搜)

思路是暴搜。 需要注意的地方是输入的方法,以及输出时的换行。 代码: /*ID: who jayLANG: C++TASK: calfflac*/#include<stdio.h>#include<string.h>#include<math.h>int main(){freopen("calfflac.in","r",stdin);freopen("calfflac.ou

usaco 1.3 Barn Repair(贪心)

思路:用上M块木板时有 M-1 个间隙。目标是让总间隙最大。将相邻两个有牛的牛棚之间间隔的牛棚数排序,选取最大的M-1个作为间隙,其余地方用木板盖住。 做法: 1.若,板(M) 的数目大于或等于 牛棚中有牛的数目(C),则 目测 给每个牛牛发一个板就为最小的需求~ 2.否则,先对 牛牛们的门牌号排序,然后 用一个数组 blank[ ] 记录两门牌号之间的距离,然后 用数组 an

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

usaco 1.2 Palindromic Squares(进制转化)

考察进制转化 注意一些细节就可以了 直接上代码: /*ID: who jayLANG: C++TASK: palsquare*/#include<stdio.h>int x[20],xlen,y[20],ylen,B;void change(int n){int m;m=n;xlen=0;while(m){x[++xlen]=m%B;m/=B;}m=n*n;ylen=0;whi

usaco 1.2 Name That Number(数字字母转化)

巧妙的利用code[b[0]-'A'] 将字符ABC...Z转换为数字 需要注意的是重新开一个数组 c [ ] 存储字符串 应人为的在末尾附上 ‘ \ 0 ’ 详见代码: /*ID: who jayLANG: C++TASK: namenum*/#include<stdio.h>#include<string.h>int main(){FILE *fin = fopen (

usaco 1.2 Milking Cows(类hash表)

第一种思路被卡了时间 到第二种思路的时候就觉得第一种思路太坑爹了 代码又长又臭还超时!! 第一种思路:我不知道为什么最后一组数据会被卡 超时超了0.2s左右 大概想法是 快排加一个遍历 先将开始时间按升序排好 然后开始遍历比较 1 若 下一个开始beg[i] 小于 tem_end 则说明本组数据与上组数据是在连续的一个区间 取max( ed[i],tem_end ) 2 反之 这个

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &