USACO18DEC部分题 补题报告

一、Convention S

P5119 [USACO18DEC] Convention S

题意

给定大巴的数量,容量,奶牛的数量和到来的时间,要求合理安排大巴的发车时间使奶牛的等待时间最小,求出奶牛最大等待时间的最小值

思路

本题使用二分,输入之后进行排序,右端点为时间最大差值,二分中计算当前限制的等待时间下所需大巴数量,满足则向左继续二分,不满足则向右继续二分,直至左右端点同为一点

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,c,t[100005],cnt,b[100005];
int main(){
//	freopen("convention.in","r",stdin);
//	freopen("convention.out","w",stdout);
	scanf("%d%d%d",&n,&m,&c);
	for(int i=1;i<=n;i++){
		scanf("%d",&t[i]);
	}
	sort(t+1,t+n+1);
	int l=0,r=t[n]-t[1];
	while(l<r){
		int mid=(l+r)/2;
		int k=1,j=1;
		for(int i=1;i<=n;i++){
			if(t[i]-t[j]>mid||i-j+1>c){
				j=i;
				k++;
			}
		}
		if(k<=m){
			r=mid;
		}
		else{
			l=mid+1;
		}
	}
	printf("%d\n",l);
//	fclose(stdin);
//	fclose(stdout);
    return 0;
}

二、Convention II S

P5120 [USACO18DEC] Convention II S

题意

给定奶牛的数量以及每个奶牛吃草的开始时间和吃草的用时,按照资历顺序输入,计算所有奶牛在队伍里等待的时间的最大值

思路

首先使用结构体记录每个奶牛的吃草开始时间,吃草用时和她的资历,然后按照到达时间的顺序进行排序,若时间相同,靠资历排序,然后按照时间顺序遍历每一只奶牛,若奶牛到达时有奶牛在吃,她必须等待(当前时间大于等于她到达的时间),就把她放进队列里比较,若她来时草地是空的(当前时间小于她到达的时间)且队列不为空(前面有需要等待的奶牛),我们就需要处理队列中的牛了,把当前时间和最长等待时间更新,进行完第二种情况的操作后,有可能处理完队列中的牛(队列为空),需要更新当前时间,有可能没有处理完队列里所有的奶牛当前时间就超过当前奶牛的到达时间了,我们就需要把这个奶牛也放到队列里去,遍历结束之后我们就可以得到最大的等待时间了

值得注意的是,这个题中我们用到了优先队列,优先队列的排序应按照奶牛的资历来进行,资历大的放前面,所以我们需要进行一个重载运算符的操作

代码

#include<bits/stdc++.h>
using namespace std;
struct node{
	int id;
	long long a,t;
}cow[100005];
bool cmp(node x,node y){
	if(x.a!=y.a){
		return x.a<y.a;
	}
	return x.id<y.id;
}
bool operator < (node x,node y){
	return x.id>y.id;
}
long long zeit,mtime,n;
priority_queue<node> q;
int main(){
//	freopen("convention.in","r",stdin);
//	freopen("convention.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		cow[i].id=i;
		scanf("%lld%lld",&cow[i].a,&cow[i].t);
	}
	sort(cow+1,cow+1+n,cmp);
	for(int i=1;i<=n;i++){
		node c;
		if(cow[i].a<=zeit){
			c.id=cow[i].id,c.a=cow[i].a,c.t=cow[i].t;
			q.push(c);
			continue;
		}
		while(cow[i].a>zeit&&!q.empty()){
			c=q.top();
			q.pop();
			mtime=max(mtime,zeit-c.a);
			zeit+=c.t;
		}
		if(!q.empty()){
			c.id=cow[i].id,c.a=cow[i].a,c.t=cow[i].t;
			q.push(c);
			continue;
		}
		zeit=cow[i].a+cow[i].t;
	}
	printf("%d",mtime);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

三、Mooyo Mooyo S

P5121 [USACO18DEC] Mooyo Mooyo S

题意

给定n和k以及棋盘的初始状态,棋盘是高n格,宽10格,每个格都有1,2,3,…,9共9种颜色,0代表空气,超过k个相同颜色的联通块会被消掉,然后其他格子受重力影响会落到底处,求最终的棋盘的状态

思路

题意就是计算联通块的数量,若大于给定的k就消掉(标记成0),然后把悬空的块都转移到地上,具体计算联通块的数量需要利用dfs,还需要定义一个布尔数组来确定是否被访问过,被访问过的格子不能再次访问,当然,每次操作结束后它都需要初始化,一旦统计出来的联通块数量超过了k,把所有访问过的点都赋值为‘0’,接下来就要进行下落的过程,这个过程需要倒着进行,从下向上进行,若发现有块,就需要尽可能的把它向下平移,到达下面有块或者棋盘界限的地方,整个过程大概就是这样的,我们还需要建立布尔变量来判断是否有活动(块下落或是消块),若没有,说明这个状态已经稳定

代码

#include<bits/stdc++.h>
using namespace std;
int fx[5]={0,0,1,0,-1};
int fy[5]={0,1,0,-1,0};
bool visited[105][15],flag;
int sum,n,k;
char mapp[105][15];
void dfs(int x,int y,int s){
	visited[x][y]=1;
	for(int i=1;i<=4;i++){
		int xx=x+fx[i];
		int yy=y+fy[i];
		if(visited[xx][yy]==0&&mapp[xx][yy]==s) {
			sum++;
			dfs(xx,yy,s);
		}
	}
}
void down(){
	for(int i=n;i>=1;i--) {
		for(int j=1;j<=10;j++) {
			if(mapp[i][j]!='0'){
				int k=i;
				while(mapp[k+1][j]=='0'&&k<=n){
					k++;
				}
				if(k!=i){
					mapp[k][j]=mapp[i][j];
					mapp[i][j]='0';
				}
			}
		}
	}
}
int main(){
//	freopen("convention.in","r",stdin);
//	freopen("convention.out","w",stdout);
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=10;j++) {
			cin>>mapp[i][j];
		}
	}
	flag=1;
	while(flag){
		flag=0;
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=10;j++) {
				if(mapp[i][j]!='0') {
					sum=1;
					memset(visited,0,sizeof(visited));
					dfs(i,j,mapp[i][j]);
					if(sum>=k){
						for(int k=1;k<=n;k++){
							for(int l=1;l<=10;l++){
								if(visited[k][l]){
									mapp[k][l]='0';
								}
							}
						}
						flag=1;
					}
				}
			}
		}
		if(flag){
			down();
		}
	}
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=10;j++) {
			cout<<mapp[i][j];
		}
		printf("\n");
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值