Codeforces Round #541 (Div. 2)

A题: Sea Battle

题目链接:

A. Sea Battle

题目大意:

求矩形被破坏后扩展的面积

思路:

根据w1和w2的大小分情况从左至右计算

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
	int w1,h1,w2,h2;
	scanf("%d %d %d %d",&w1,&h1,&w2,&h2);
	int ans=0;
	int h=h1+1+h2+1;
	
	ans+=h;
	if(w1==w2){
		ans+=(w1+1)*(h1+h2+2)-w1*(h1+h2);
	}
	else{
		ans+=(w2+1)*(h2+1)-w2*h2+w2+1;
		ans+=(w1-w2)*(h1+2)-(w1-(w2+1))*h1;
	}
	printf("%d\n",ans); 
	return 0;
}

B题:Draw!

题目链接:

Codeforces Round #541 (Div. 2) B Draw!

题目大意:

有一对记分牌分别为a和b,在已知的条件下判断可能出现平局的总次数。

思路:

利用标记 l l l记录平局时对应的时间戳,时间戳根据a,b的读数每轮更新。

#include<iostream>
#include<cstdio>
#include<algorithm> 
using namespace std;
int t1=-1,t2=-1;//记录上一个时刻的a,b号码牌的读数,防止重复
int main(){
	int n;
	scanf("%d",&n);
	int l=0;//平局时对应的时间戳
	int ans=0;
	for(int i=0;i<n;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		if(a==t1&&b==t2) continue;//上一次出现过的直接跳过
		
		if(a<l||b<l){l=max(l,max(a,b));continue;} //这个时候时间戳l到max(a,b)均不可能出现平局,更新时间戳
		
		while(l<=min(a,b)){
			ans+=(min(a,b)-l+1);//满足条件统计次数
			l=min(a,b)+1; //时间戳前移
		}
		l=max(l,max(a,b));//更新本轮的时间戳
		t1=a;t2=b; //记录本轮出现的数据
	}
	printf("%d\n",ans);
	
	return 0;
}

C题:Birthday

题目链接:

Codeforces Round #541 (Div. 2) C Birthday

题目大意:

n n n个人围成一圈,要求任意两个人身高之差的最大值最小,输出身高之差的最大值最小时对应的排序。

思路:

看到最大值最小就二分了 q w q qwq qwq,结果自然超时…

正解:

首先排序,然后利用双端队列分别从队尾和队头插入排序后的身高,有点贪心的思想。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<deque>
#include<algorithm>
using namespace std;
deque<int> Q;
int a[110];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	
	sort(a,a+n);
	
	for(int i=0;i<n;i++){
		if(i%2==0) Q.push_back(a[i]);
		else Q.push_front(a[i]);
	} 
	
	for(auto it=Q.begin();it!=Q.end();it++){
		printf("%d ",*it);
	}
	printf("\n");
	
	return 0;
}

利用二分+dfs,超时code…

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<unordered_map>
using namespace std;
int a[110],vis[110],aft[110][110];
unordered_map<int,int> mp;
int n;
int dfs(int k,int cnt,int mid){
	if(cnt==n-1){
		if(abs(a[k]-a[1])<=mid) return 1;
	}
	
	for(int i=1;i<=n;i++){
		if(!vis[i]&&abs(a[i]-a[k])<=mid){
			vis[i]=1;
			aft[k][mp[mid]]=i;
			if(dfs(i,cnt+1,mid)) return 1;
			vis[i]=0;
		}
	}
	return 0;
}
void p(int k,int mid){//输出
	if(aft[k][mid]==-1){
		printf("%d ",a[k]);
		return;
	} 
	p(aft[k][mid],mid);
	printf("%d ",a[k]);
}
int main(){
	scanf("%d",&n);
	int maxv=0,minv=0x3f3f3f3f;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),maxv=max(maxv,a[i]);
	
	int l=0,r=maxv;
	memset(aft,-1,sizeof(aft));
	
	int num=0;
	while(l<r){//二分时间间隔
		int mid=(l+r)>>1;
		memset(vis,0,sizeof(vis));
		vis[1]=1;
		mp[mid]=num;
		num++;
		if(dfs(1,0,mid)) r=mid;
		else l=mid+1;
	}
	 
	p(1,mp[l]);
	printf("\n");
	
	return 0;
}

D题:Gourmet choice

题目链接:

Codeforces Round #541 (Div. 2) D. Gourmet choice

题目大意:

根据每道菜之间的相互之间好吃与不好吃的关系,用最小的数给每道菜评分。

思路:

根据“=”求连通分量,根据">“和”<"建图。
将相同连通分量类的记为一种颜色,在不同的连通分量之间建图。

#include<bits/stdc++.h>
using namespace std;
int n,m;
char s[1010][1010];
vector<int> eq[1010*4],g[1010*4],ans;
int col[1010*4],vis[1010*4];

int cnt[1010*4];
void dfs(int k,int color){//求连通分量,给每个节点染色,方便合并同类的节点
	col[k]=color;
	for(int nxt:eq[k]){
		if(col[nxt]==-1)
			dfs(nxt,color);
	}
}
void dfs2(int k){//计算不同染色节点之间的路径关系
	vis[k]=1;
	for(int nxt:g[k]){
		if(vis[nxt]==-1)
			dfs2(nxt);
	}
	
	ans.push_back(k);//记录不同连通分量之间的关系
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%s",s[i]);
		for(int j=0;j<m;j++){
			if(s[i][j]=='='){//合并相同的节点
				eq[i].push_back(j+n);
				eq[j+n].push_back(i);
			}
		}
	}
	
	int color=0;
	memset(col,-1,sizeof(col));
	memset(vis,-1,sizeof(vis));
	
	for(int i=0;i<n+m;i++){//染色
		if(col[i]==-1){
			dfs(i,color);
			color++;
		}
	}
	
	for(int i=0;i<n;i++){//建图
		for(int j=0;j<m;j++){
			if(s[i][j]=='>') g[col[i]].push_back(col[n+j]);
			else if(s[i][j]=='<') g[col[n+j]].push_back(col[i]);
		}
	}

	for(int i=0;i<color;i++){//寻找不同染色区域之间的关系
		if(vis[i]==-1){
			dfs2(i);
		}
	}
	
	for(int nxt:ans){//统计结果
		int mx=0;
		for(int to:g[nxt]){
			if(!cnt[to]){
				printf("No\n");
				return 0;
			}
			mx=max(mx,cnt[to]);
		}
		cnt[nxt]=mx+1;
	}
	
	printf("Yes\n");
	for(int i=0;i<n;i++) printf("%d ",cnt[col[i]]);
	printf("\n");
	
	for(int j=0;j<m;j++) printf("%d ",cnt[col[j+n]]);
	return 0;
}

F题:Asya And Kittens

题目链接:

Codeforces Round #541 (Div. 2) F. Asya And Kittens

题目大意:

每个动物想要和相邻隔板内的动物玩耍,每次只能取消一个隔板,求出原来动物关押的顺序。

思路:

并查集,构造。在原来的n的笼子的基础上增加n-1个笼子,使得之前笼子里面的动物以增加后的笼子为父亲节点,由于动物每次只和相邻的同伴玩耍,可以将上面的并查集得到的结果建立成一棵树,然后遍历到根节点,当根节点的数小于等于n的时候输出。
根据样例建成的树如下:

				9
			   /  \
			  8    7
			 / \   / \
			6  3  2   5
		   / \
		  1   4

code:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int f[150010*2];
//vector<int> ed[150010];
int l[150010*2],r[150010*2];
int n;

int fd(int x){
	if(x==f[x]) return f[x];
	return f[x]=fd(f[x]);
}
void dfs(int k){//遍历到叶子节点输出
	if(k<=n) {
		printf("%d ",k);
		return;	
	}
	else{
		dfs(l[k]);
		dfs(r[k]);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n*2;i++) f[i]=i;
	
	for(int i=1;i<=n-1;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		int t1=fd(x),t2=fd(y);
		f[t1]=f[t2]=f[i+n]=i+n;//记录每个笼子对应的父亲节点
		
		l[i+n]=t1;//左节点
		r[i+n]=t2;//右节点
	}

	dfs(n+n-1);
	return 0; 
}
posted @ 2019-03-06 08:34  xzhws  阅读(45)  评论(0编辑  收藏  举报