文章目录
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;
}