Codeforces Round 936 (Div.2)

A.

思路:先假设一组数122233,总数有6个,中位数为6/2=3,我们如果选择中位数2加1,此时改的这个数2已不再中位数的位置,此数组变为122333,此时中位数还是2未发生改变,因此我们就可以知道,操作数即为改中位数往后与它相同的数的数量,另外还要清楚他那个符号是向上取整,所以7/2 = 3······1 = 4,代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e5+10;

int a[N];

void solve()
{
	int n;
	cin >> n;
	
	for(int i = 1; i <= n; i++) cin >> a[i];
	sort(a+1, a+1+n);

	if(n&1) n++; //奇数加一,作用类似于向上取整
	
	int mid = n/2;
	int idx = n/2;
	
	int ans = 0;
	
	while(a[idx] == a[mid]&&idx <= n) idx++;
	
	ans = idx - mid;
	cout << ans << endl;
	memset(a, 0, sizeof a);//一定不要忘了将数组清零啊
}

int main()
{
	int t;
	cin >> t;
	while(t--)
	{
		solve();
	}
	return 0;
}

B.

思路:先统计出数组最大的连续子数组和,再通过观察可发现,其数值增加是2的等比数列,因此计算下它的等比数列和即可(可以用快速幂,不过好像也不需要),取模的时候要注意下,代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

#define int long long

const int N = 2e5+10, mod = 1e9+7;

int a[N];

int qmi(int b, int k, int p)
{
	int res = 1;
	while(k)
	{
		if(k&1) res = (long long)res * b%p;
		b = (long long)b*b%mod;
		k >>= 1;
	}
	return res;
}

void solve()
{
	int n, k; cin >> n >> k;
	int sum = 0;
	for(int i = 1; i <= n; i++) 
	{
		cin >> a[i];
		sum += a[i];

	}
	
	sum%=mod;
	int maxSum = a[1];
	int x = a[1];
	
	for(int i = 2; i <= n; i++)
	{
		x = (x > 0) ? x + a[i] : a[i];
		maxSum = (x > maxSum) ? x : maxSum;
	}
	
	if(maxSum < 0) maxSum = 0;

    //maxSum一定要先模上mod后再乘,就这个导致了溢出没过
	maxSum = maxSum % mod * (qmi(2, k, mod)-1)%mod;
	
	sum = ((sum + mod) % mod + maxSum) % mod;
	
	cout << sum << endl;
	
	memset(a, 0,sizeof a);
}

signed main()
{
	int t;
	cin >> t;
	while(t--)
	{
		solve();
	}
	return 0;
}

C.听大佬说这是个比较典的题(但我不会,值得学习)

思路:首先这是个寻找最小的最大值 --> 二分,所以我们可以从1到n进行二分,找到这个x,二分出一个x时,我们可以用dfs进行寻找满足x的长度进行切割,最后统计可以切割出的数量,并与k进行比较,如果大于k,返回true,否则返回false。至于为啥是大于而不是大于等于,因为我统计的是子树的数量,移除k条边产生k+1个子树,所以要大于k,代码如下:

​
#include <iostream>
#include <vector>

using namespace std;

const int N = 1e5+10;

vector<int> v[N];

int n, m;
int cnt;
//运用贪心,够切了就进行切,产生一子树
int dfs(int u, int p, int t)
{
	int num = 1;
	for(auto x : v[u])
	{
		if(x == p) continue;
		num += dfs(x, u, t);
	}
	
	if(num >= t) //只有节点数量满足条件后,子树数量加1
	{
		cnt++; 
		return 0;//把这个子树切掉,对自己的父亲就没有贡献
	}
	
	return num;
}

bool check(int x)
{
	cnt = 0;
	dfs(1, -1, x);
	return cnt >= m+1;
}

void solve()
{
	cin >> n >> m;
	
	int a, b;
	for(int i = 1; i < n; i++)
	{
		cin >> a >> b;
		v[a].push_back(b);
		v[b].push_back(a);
	}
	
	int l = 1, r = n;
	while(l < r)
	{
		int mid = (l + r + 1) >> 1;
		if(check(mid)) l = mid;
		else r = mid-1;
	}
	
	cout << l << endl;
	
	for(int i = 1; i <= n; i++) v[i].clear();
	
}

int main()
{
	int t;
	cin >> t;
	while(t--)
	{
		solve();
	}
	return 0;
}

​

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值