Codeforces Round 936 (Div. 2)

下次千万别在csdn里直接编辑,没保存,全没了!!!

A. Median of an Arra

排个序,找到中位数,从中位数开始往后数有几个数和中位数相等

cpp 复制代码
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int n;
void solve() {
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+1+n);
	if(n%2==0){
		int x=n/2;
		int cnt=1;
		for(int i=x+1;i<=n;i++){
			if(a[i]==a[i-1]) cnt++;
			else break;
		}
		cout<<cnt<<endl;
	}
	else{
		int x=(n+1)/2;
		int cnt=1;
		for(int i=x+1;i<=n;i++){
			if(a[i]==a[i-1]) cnt++;
			else break;
		}
		cout<<cnt<<endl;
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t=1;
    cin>>t;
	while(t--) {
		solve();
	}
	return 0;
}

B. Maximum Sum

求出最大子段和,记为sum,每次把sum与和最大的子段放在一起

cpp 复制代码
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10,mod=1e9+7;
int a[N];
int n,k;
int dp[N];
void solve() {
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	dp[0]=0;
	for(int i=1;i<=n;i++){
		dp[i]=max(a[i],dp[i-1]+a[i]);
	}
	int sum=0;
	for(int i=1;i<=n;i++) sum=max(sum,dp[i]);
//	cout<<sum<<endl;
	int ans=sum%mod;
	for(int i=1;i<k;i++){
		sum=(sum+sum)%mod;
		ans=(ans+sum)%mod;
	}
	for(int i=1;i<=n;i++) ans=(ans+a[i])%mod;
	cout<<(ans+mod)%mod<<endl;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t=1;
    cin>>t;
	while(t--) {
		solve();
	}
	return 0;
}

C. Tree Cutting

n个节点的树,刚好删除k条边,问剩余连通块大小最小的最大值

最小的最大值==>二分答案

对于二分出的连通块大小最小的最大值,dfs一遍,统计满足答案的情况下最多能分成多少个连通块,如果个数大于等于k+1,那么合法,取一堆合法中最大的那个

trick:

1.最小的最大值==>平均分或者二分答案

2.对于树,是否要dfs:如果树的具体形态不同,答案千差万别,那么肯定要dfs

cpp 复制代码
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,k;
map<int,vector<int>>e;
int cnt;
int dfs(int u,int fa,int target){
	int now=1;
	for(auto v:e[u]){
		if(v==fa) continue;
		now+=dfs(v,u,target);
	}
	if(now>=target){
		cnt++;
		return 0;
	}
	return now;
}
bool check(int x){
	cnt=0;
	dfs(1,-1,x);
	if(cnt>=k+1) return true;
	return false;
}
void solve() {
	cin>>n>>k;
	e.clear();
	for(int i=0;i<n-1;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	int l=1,r=n;
	while(l<r){
		int mid=(l+r+1)/2;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	cout<<l<<endl;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t=1;
    cin>>t;
	while(t--) {
		solve();
	}
	return 0;
}

总结:

这一阶段的目标是出A,B,C,本次比赛只出了A,B

A,B的思路都是很快就有的,没有什么卡顿,20分钟就出了,完全没有问题

现分析一下没有做出C题的原因

1.看到最小的最大值,立马想到平均分,把二分答案这一条路pass了,导致方向偏了,以后需要两条路都尝试

2.之前做过几道树的题目是不需要dfs的,只用分析度数,于是往这个方向想了很久,方向偏了,具体判断是否需要dfs的方法:如果树的具体形态不同,答案千差万别,那么肯定要dfs

3.对于dfs的熟练度不够,特别是对于归(递归的归)的理解,一般是求子树的大小,子树的权值和,子树的异或和

方法是记住哪个地方是归(递归的归),看以下代码注释

cpp 复制代码
int dfs(int u,int fa,int target){
	int now=1;
	for(auto v:e[u]){
		if(v==fa) continue;
		now+=dfs(v,u,target);//从u往下递v这个分支,然后归回来了
	}
    //从u往下递完所有的分支,然后归回来了
	if(now>=target){
		cnt++;
		return 0;//返回0表示以u为根的子树自成一个连通块
	}
	return now;
}

另外分析一下做题的节奏以及心态

掌握好做题节奏,就我目前所知,自认为最好的方法就是一边读题一边用自己的话在记事本上记录,然后思考的东西也一并记在记事本上,同时计时,一般想10到20分钟没有一点思路的话,那么就可以放弃这道题了

这样做有以下几个好处:1.心态比较平稳,不容易急 2.题目读的仔细,不容易读错题 3.做完题目的同时写完了题解

心态上:现场赛焦急是正常的,只要按照以上的步骤,按部就班,掌握好做题的节奏就没问题

如果遇到不会做的题目该怎么办(比如这场比赛的C题,不包括超出能力范围的题):

方向思考错了真的很难走出自己的思维定势,只能重新慢慢读题,抛掉之前的思路,重新慢慢想,也得看看运气,因为很难跳出自己之前的思维,可以适时放弃

相关推荐
zh_xuan2 小时前
c++ 类的语法3
开发语言·c++
一律清风3 小时前
【Opencv】canny边缘检测提取中心坐标
c++·opencv
金融小师妹4 小时前
应用BERT-GCN跨模态情绪分析:贸易缓和与金价波动的AI归因
大数据·人工智能·算法
广州智造4 小时前
OptiStruct实例:3D实体转子分析
数据库·人工智能·算法·机器学习·数学建模·3d·性能优化
Trent19856 小时前
影楼精修-肤色统一算法解析
图像处理·人工智能·算法·计算机视觉
feifeigo1236 小时前
高光谱遥感图像处理之数据分类的fcm算法
图像处理·算法·分类
a东方青7 小时前
蓝桥杯 2024 C++国 B最小字符串
c++·职场和发展·蓝桥杯
北上ing7 小时前
算法练习:19.JZ29 顺时针打印矩阵
算法·leetcode·矩阵
.格子衫.8 小时前
真题卷001——算法备赛
算法
XiaoyaoCarter8 小时前
每日一道leetcode
c++·算法·leetcode·职场和发展·二分查找·深度优先·前缀树