下次千万别在csdn里直接编辑,没保存,全没了!!!
A. Median of an Arra
排个序,找到中位数,从中位数开始往后数有几个数和中位数相等
#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与和最大的子段放在一起
#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
#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的熟练度不够,特别是对于归(递归的归)的理解,一般是求子树的大小,子树的权值和,子树的异或和
方法是记住哪个地方是归(递归的归),看以下代码注释
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题,不包括超出能力范围的题):
方向思考错了真的很难走出自己的思维定势,只能重新慢慢读题,抛掉之前的思路,重新慢慢想,也得看看运气,因为很难跳出自己之前的思维,可以适时放弃