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题,不包括超出能力范围的题):

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

相关推荐
浮生如梦_1 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
青花瓷5 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
观音山保我别报错5 小时前
C语言扫雷小游戏
c语言·开发语言·算法
幺零九零零6 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
TangKenny6 小时前
计算网络信号
java·算法·华为