20234.7.20csp-j第二场模拟赛赛后总结

T1:

https://www.luogu.com.cn/problem/P5116https://www.luogu.com.cn/problem/P5116

T2:

https://www.luogu.com.cn/problem/P5119https://www.luogu.com.cn/problem/P5119

T3:

https://www.luogu.com.cn/problem/P5121https://www.luogu.com.cn/problem/P5121

T4:

https://www.luogu.com.cn/problem/P2052https://www.luogu.com.cn/problem/P2052

T1:农业,尤其是生产牛奶,是一个竞争激烈的行业。Farmer John 发现如果他不在牛奶生产工艺上有所创新,他的乳制品生意可能就会受到重创!

幸运的是,Farmer John 想出了一个好主意。他的三头获奖的乳牛,Bessie、Elsie 和 Mildred,各自产奶的口味有些许不同,他打算混合这三种牛奶调制出完美的口味。

为了混合这三种不同的牛奶,他拿来三个桶,其中分别装有三头奶牛所产的奶。这些桶可能有不同的容积,也可能并没有完全装满。然后他将桶 1 的牛奶倒入桶 2,然后将桶 2 中的牛奶倒入桶 3,然后将桶 3 中的牛奶倒入桶 1,然后再将桶 1 的牛奶倒入桶 2,如此周期性地操作,共计进行 100 次(所以第100 次操作会是桶 1 倒入桶 2)。当 Farmer John 将桶 a 中的牛奶倒入桶 b 时,他会倒出尽可能多的牛奶,直到桶 a 被倒空或是桶 b 被倒满。

请告诉 Farmer John 当他倒了100 次之后每个桶里将会有多少牛奶。

按照题意模拟,用for循环。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int c[4],m[4];//c数组是容量,m数组是桶里牛奶的数量 
int main()
{
	for(int x=1;x<=3;x++)cin>>c[x]>>m[x];//输入 
	for(int x=1;x<=100;x++){//循环模拟100次
		int f=(x-1)%3+1,s;//f是要将牛奶倒出的桶,s则是倒入的桶
		if(f==3)s=1;//桶3要倒给桶1
		else s=f+1;//否则就倒给下一个桶
		int mi=min(c[s]-m[s],m[f]);//mi是倒牛奶的数量,取桶s剩余容积和桶f牛奶数量的最小值 
		m[f]-=mi;//桶f倒出 
		m[s]+=mi;//桶s倒入 
	}
	cout<<m[1]<<endl<<m[2]<<endl<<m[3];//输出 
	return 0;
}

错因:未开long long

T2:

题面:一场别开生面的牛吃草大会就要在 Farmer John 的农场举办了!

世界各地的奶牛将会到达当地的机场,前来参会并且吃草。具体地说,有 N 头奶牛到达了机场,其中奶牛 i 在时间 t到达。Farmer John 安排了 M(1≤1051≤M≤105)辆大巴来机场接这些奶牛。每辆大巴可以乘坐 C 头奶牛(1≤1≤C≤N)。Farmer John 正在机场等待奶牛们到来,并且准备安排到达的奶牛们乘坐大巴。当最后一头乘坐某辆大巴的奶牛到达的时候,这辆大巴就可以发车了。Farmer John 想要做一个优秀的主办者,所以并不想让奶牛们在机场等待过长的时间。如果 Farmer John 合理地协调这些大巴,等待时间最长的奶牛等待的时间的最小值是多少?一头奶牛的等待时间等于她的到达时间与她乘坐的大巴的发车时间之差。

输入保证 MC≥N。

题目分析:本题可以采用二分答案的方法解决。

先将牛到达的时间排序,然后二分最长等待时间即可。

详细过程已经在代码里注释说明,这里不再赘述。

cpp 复制代码
#include <cstdio>
#include <algorithm>
using namespace std;
int a[100005];
int main(){
 //freopen("convention.in","r",stdin);
 //freopen("convention.out","w",stdout);
 int n,m,c;
 scanf("%d%d%d",&n,&m,&c);
 for(int i=1;i<=n;i++)
  scanf("%d",&a[i]);
 sort(a+1,a+n+1);
 int l=0,r=a[n]-a[1];
 while(l<r) {
  int mid=(l+r)>>1,cnt=1,sta=1;
  for(int i=1;i<=n;i++)
   if(a[i]-a[sta]>mid||i-sta+1>c)   {
   	cnt++;
   	sta=i;
   }
  if(cnt<=m)r=mid;
  else l=mid+1;
 }
 cout<<l;
 return 0;
}

错因:未考虑到要用二分。

T3:由于手上(更确实的,蹄子上)有大把的空余时间,Farmer John 的农场里的奶牛经常玩电子游戏消磨时光。她们最爱的游戏之一是基于一款流行的电子游戏 Puyo 的奶牛版;名称当然叫做 Mooyo 。

Mooyo 是在一块又高又窄的棋盘上进行的游戏,高 N(1≤N≤100)格,宽 10 格。 这是一个 N=6 的棋盘的例子:

每个格子或者是空的(用 0表示),或者是九种颜色之一的干草捆(用字符 1...9 表示)。重力会使得干草捆下落,所以没有干草捆的下方是 00。

如果两个格子水平或垂直方向直接相邻,并且为同一种非 00 颜色,那么这两个格子就属于同一个连通区域。任意时刻出现至少 K 个格子构成的连通区域,其中的干草捆就会全部消失,变为 00。如果同时出现多个这样的连通区域,它们同时消失。随后,重力可能会导致干草捆向下落入某个变为 0的格子。由此形成的新的布局中,又可能出现至少 K 个格子构成的连通区域。若如此,它们同样也会消失(如果又有多个这样的区域,则同时消失),然后重力又会使得剩下的方块下落,这一过程持续进行,直到不存在大小至少为K的连通区域为止。

给定一块 Mooyo棋盘的状态,输出这些过程发生之后最终的棋盘的图案。

输入样例:

复制代码
6 3
0000000000
0000000300
0054000300
1054502230
2211122220
1111111223

输出样例:

复制代码
0000000000
0000000000
0000000000
0000000000
1054000000
2254500000

题目分析:

看到矩阵又看到连块,当然是用dfs了。

直接搜索连块,顺便消除嘛。

但是它必须在连块达到一定个数时才可消除。在搜索中累加到一定个数再清除会有bug,之前返回的快是清除不到的。所以要另外加一个函数来清除连块。

还有一个重要的部分就是下降,因为是每列下降,所以以列为单位,从下往上搜,每找到一个非零数,都与当前列最下方的0互换。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int n,k,st;
int dx[4]= {-1,0,1,0};
int dy[4]= {0,1,0,-1};
char s[101][11];
bool f[101][11],flag=true,fl;
void dfs(int x,int y) {
	if(st>=k)fl=true;
	f[x][y]=1;
	for(int i=0; i<4; i++) {
		int tx=x+dx[i];
		int ty=y+dy[i];
		if(tx>0&&ty>0&&tx<=n&&ty<=10&&!f[tx][ty]&&s[tx][ty]==s[x][y]) {
			st++;
			dfs(tx,ty);
		}
	}
}
void dfs2(int x,int y) {
	f[x][y]=1;
	for(int i=0; i<4; i++) {
		int tx=x+dx[i];
		int ty=y+dy[i];
		if(tx>0&&ty>0&&tx<=n&&ty<=10&&s[tx][ty]!='0'&&s[tx][ty]==s[x][y]&&!f[tx][ty]) {

			dfs2(tx,ty);
		}
	}
	s[x][y]='0';
}
int main() {
	cin>>n>>k;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=10; j++) {
			cin>>s[i][j];
		}
	}
	while(flag) {
		flag=0;
		memset(f,0,sizeof(f));
		for(int i=1; i<=n; i++) {
			for(int j=1; j<=10; j++) {
				if(!f[i][j]&&s[i][j]!='0') {
					st=1;
					fl=false;
					dfs(i,j);
					if(fl)flag=true;
					memset(f,0,sizeof(f));
					if(fl)dfs2(i,j);
				}
			}
		}
		for(int i=1; i<=10; i++) {
			int pos=n;
			for(int j=n; j>=1; j--) {
				if(s[j][i]!='0')swap(s[j][i],s[pos--][i]);
			}
		}
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=10; j++) {
			cout<<s[i][j];
		}
		cout<<endl;
	}
	return 0;
}

错因:不会让方块下落

T4:

在 W 星球上有 n 个国家。为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通。但是每个国家的国王都很吝啬,他们只愿意修建恰好 n−1 条双向道路。

每条道路的修建都要付出一定的费用,这个费用等于道路长度乘以道路两端 的国家个数之差的绝对值。例如,在下图中,虚线所示道路两端分别有 2 个、4 个国家,如果该道路长度为 1,则费用为 1×∣2−4∣=2。图中圆圈里的数字表示国家的编号。

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5+3;
int n, fir[maxn], nx[maxn], u[maxn], v[maxn], w[maxn], s[maxn], Ans;
bool vis[maxn];
inline int DFS(int x, int fr) {
	if(s[x] != 1) return s[x];
	int k = fir[x];
	while (k != -1) {
		if(fr != v[k]) {
			s[x] += DFS(v[k], x);
			Ans += abs(n-2*s[v[k]]) * w[k];
		}
		k = nx[k];
	}
	return s[x];
}

main() {
	cin>>n;
	memset(fir, -1, sizeof fir);
	fill(s+1, s+1+n, 1);
	for(int i=1; i<=(n-1)*2; i++) {
		cin>>u[i]>>v[i]>>w[i]);
		nx[i] = fir[u[i]];
		fir[u[i]] = i;
		u[i+1] = v[i], v[i+1] = u[i], w[i+1] = w[i];
		i++;
		nx[i] = fir[u[i]];
		fir[u[i]] = i;
	}
	vis[1] = 1;
	DFS(1, 1);
	cout<<Ans;
}

错因:没思路

总结"本次考试T1,T2有不该丢的分,T34都因为DFS,树掌握不牢。要继续巩固后面知识

相关推荐
xiaoshiguang33 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡3 小时前
【C语言】判断回文
c语言·学习·算法
别NULL3 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇3 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
CYBEREXP20084 小时前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
ZSYP-S4 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos4 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos4 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习4 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA5 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法