Codeforces Round 963 (Div. 2)

A. Question Marks

解析:如果答案为A,B,C,D且他们的数量不大于n,则正确答案数量+1

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
multiset<int>s1,s2;
int a[N];
string s[N];
vector<int>e[N];
int vis[2*N];
int flag;
void solved() {
	int n;
	cin>>n;
	string s;
	cin>>s;
	map<int,int>mp;
	int ans=0;
	for (int i=0;i<4*n;i++){
		if (s[i]!='?'){
			if (mp[s[i]]<n){
				ans+=1;
				mp[s[i]]+=1;	
			}
		}
	}
	cout<<ans<<"\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	// T = 1;
	cin >> T;
	while (T--) {
		solved();
	}
	return 0;
}

B. Parity and Sum

解析:
因为一个偶数加一个奇数,结果一定是一个奇数,所以替换之后肯定会比原来多一个大奇数。
因此我们可以每次用当前最大的奇数与最小的偶数进行替换,最优情况代价是偶数的数量。
但是可能会出现一个情况就是我当前最大的奇数,比当前最小的偶数要小。
所以这时候会花费次数在这上面,但是我们可以一开始用最大的奇数与最大的偶数替换。
这时候得到的奇数肯定是最大的,而且额外花费的次数只用了一次,这个情况代价是偶数数量+1。
因此我们取min(最大奇数与最小偶数进行替换的代价,偶数数量+1)

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int a[N];
void solve() {
	int n;
	cin>>n;
	for (int i=1;i<=n;i++){
		cin>>a[i];
	}
	int ans=0;
	priority_queue<int>j,o;
	int maxxo=0,maxxj=0;
	int flag=0;
	for (int i=1;i<=n-1;i++){
		if (a[i]%2!=a[i+1]%2){
			flag=1;
		}
		if (a[i]%2==0){
			o.push(-a[i]);
		//	maxxo=max(a[i],maxxo);
		}else{
			j.push(a[i]);
		//	maxxj=max(a[i],maxxj);
		}
	}
	if (a[n]%2){
		j.push(a[n]);
	}else{
		o.push(-a[n]);
	}
	int x=o.size();
	int minn=1e18;
	if (!flag){
		cout<<"0\n";
		return;
	}else{
		while (!o.empty()){
			int ans1=-o.top();
			int ans2=j.top();
			int ans3=ans1+ans2;
			//o.pop();
			j.pop();
			if (ans1<ans2){
				o.pop();
			}
			j.push(ans3);
			ans+=1;
		}
	}
	minn=min(ans,x+1);
	cout<<minn<<"\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	// T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

C. Light Switches

解析:
房间所有灯全亮的最短时间只会出现在最后一盏灯亮的时段。
那我们判断这段时间是否会有n盏灯同时亮的时刻即可。
我是用了一个map前缀和,来判断是否有全亮的时候。

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int a[N];
void solve() {
	map<int,int>mp;
	int n,k;
	cin>>n>>k;
	int maxx=0;
	for (int i=1;i<=n;i++){
		cin>>a[i];
		maxx=max(a[i],maxx);
	}
	sort(a+1,a+1+n);
	for (int i=1;i<=n;i++){
		int x=maxx-a[i];
		int res=x%k;
		if (x/k%2){
			mp[(k-1)-res+maxx+1]+=1;
		}else{
			mp[maxx-res]+=1;
			mp[(k-1)-res+maxx+1]-=1;
		}
	}
	int ans=0;
	for (auto it:mp){
		if (it.first>=maxx+k){
			break;
		}
	//	cout<<it.first<<" "<<it.second<<" "<<ans<<"***\n";
		ans+=it.second;
		if (ans>=n){
			cout<<it.first<<"\n";
			return;
		}
	}
	cout<<"-1\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	// T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

D. Med-imize

解析:
我们可以根据中位数的性质,子数组中肯定会有(n+1)/2个数字大于等于中位数。
因此我们可以选择二分答案中位数。
判断符合要求的子数组中是否有大于等于(n+1)/2个数字大于等于中位数
接下来就是如何写check里面的东西了。
因为你正常枚举剩下的,需要O(n),还得排序,外面套个二分,就得O(n2lgn2)的复杂度。
因此我们还需要发现一些性质去优化时间。
数组删去之后剩下的肯定会小于等于k,我们可以发现剩下这些位置%k,是按1,2,3…,0这样排序的。
比如4,8,8,5,4,3,1,2。此时k等于3,那么剩下的可以是1,2,它们坐标对应7,8正好mod3等于1,2。
我们可以算出剩下子数组的大小,也就是(n-1)%k+1,这样可以避免n%k=0的情况。
因此我们选择的每一个下标(i-1)%k+1必须小于等于(n-1)%k+1。
这样就像找一个递增子序列里面大于等于mid的数量最多,我们可以考虑DP。
因为我们所选择的子数组下标是按1,2,3,4…(n-1)%k+1,1,2,3,4,…,(n-1)%k+1这样循环的,所以DP i的时候可以从前一个继承,也可以继承上一轮的。
我写的是原地滚动,理解可能会不好一点
在这里插入图片描述
也有不是原地滚动,但原理都一样
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int a[N];
int dp[N];
int n,k;
int check(int mid) {
	for (int i=0; i<=n; i++) {
		dp[i]=0;
	}
	int ans=0;
	int maxx=0;
	for (int i=0; i<n; i++) {
		if (i%k>(n-1)%k) {
			continue;
		}
		if (i%k==0) {
			if (a[i]>=mid){
				dp[i]=1;
			}
		} else {
			if (a[i]>=mid) {
				dp[i]=dp[i-1]+1;
			}else{
				dp[i]=dp[i-1];
			}
		}
		if (i>=k){
			dp[i]=max(dp[i],dp[i-k]);
		}
		if (dp[i]>((n-1)%k+1)/2){
			//cout<<"111\n";
			return 1;
		}
	}
	return 0;
}
void solve() {
	cin>>n>>k;
	map<int,vector<int>>mp;
	for (int i=0;i<n; i++) {
		cin>>a[i];
	}
	if (n<=k) {
		sort(a,a+n);
		cout<<a[(n-1)/2]<<"\n";
		return;
	}
	for (int i=0; i<=n; i++) {
		dp[i]=0;
	}
	int l=0,r=1e10;
	while (l+1<r) {
		int mid=(l+r)/2;
		if (check(mid)) {
			l=mid;
		} else {
			r=mid;
		}
	}
	cout<<l<<"\n";
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	// T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值