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

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

相关推荐
xiaoshiguang32 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡2 小时前
【C语言】判断回文
c语言·学习·算法
别NULL2 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇2 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
CYBEREXP20083 小时前
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实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA4 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法