Codeforces Round 963 (Div. 2)

https://codeforces.com/contest/1993


A. Question Marks

解析:简单题,略

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
typedef long long LL;
//#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 1e5 + 10, M = 1e6 + 10;
int n;
char s[N];

signed main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n;
		scanf("%s", s + 1);
		int A, B, C, D;
		A = B = C = D = 0;
		for (int i = 1; i <= 4*n; i++) {
			if (s[i] == 'A') {
				A++;
			}
			else if (s[i] == 'B') {
				B++;
			}
			else if (s[i] == 'C') {
				C++;
			}
			else if (s[i] == 'D') {
				D++;
			}
		}
		int ans = 0;
		ans += min(A, n);
		ans += min(B, n);
		ans += min(C, n);
		ans += min(D, n);
		printf("%d\n", ans);
	}
	return 0;
}

B. Parity and Sum

解析:简单题,略

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
typedef long long LL;
#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 2e5 + 10, M = 1e6 + 10;
int n;
bool cmp(const int& a, const int& b) {
	return a > b;
}
signed main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n;
		vector<int>e, o;
		e.reserve(n + 10), o.reserve(n + 10);
		for (int i = 1; i <= n; i++) {
			int a;
			scanf("%lld", &a);
			if (a % 2) {
				o.push_back(a);
			}
			else {
				e.push_back(a);
			}
		}
		sort(o.begin(), o.end());
		sort(e.begin(), e.end(),cmp);
		if (o.size() == 0 || e.size() == 0) {
			cout << 0 << endl;
			continue;
		}
		int mx = o[o.size() - 1];
		int ans1 = 0;
		for (int i = 0; i < e.size(); i++) {
			do {
				mx = mx + e[i];
				ans1++;
			} while (mx - e[i] < e[i]);
			//cout << "__________" << mx << " " << e[i] << endl;
			//e[i] = mx;
		}
		sort(e.begin(), e.end());
		mx = o[o.size() - 1];
		int ans2 = 0;
		for (int i = 0; i < e.size(); i++) {
			do {
				mx = mx + e[i];
				ans2++;
			} while (mx - e[i] < e[i]);
			//cout << "__________" << mx << " " << e[i] << endl;
			//e[i] = mx;
		}
		printf("%lld\n", min(ans1, ans2));
	}
	return 0;
}

/*
7
5
1 3 5 7 9
4
1 4 10 20
3
2 3 4
4
3 2 2 8
6
4 3 6 1 2 1
6
3 6 1 2 1 2
5
999999996 999999997 999999998 999999999 1000000000


*/

C. Light Switches

解析:

易发现每个灯的状态都是以 2k 为周期变化的,要想所有等都亮,则需要所有的灯在某一个 (r,r-k+1) 的区间内都亮。

所以可以将所有的 ai 都 mod (2*k),再用双指针找到这个区间。

因为最终答案 s >=max(a) 的,所以

最终的答案 s=max+(r-max)%(2*m)

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
typedef long long LL;
//#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 2e5 + 10, M = 1e6 + 10;
int n, m;


signed main() {
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;
		vector<int>d(4 * m+2, 0);
		int mx = -1;
		int p = 2 * m;
		for (int i = 1; i <= n; i++) {
			int a;
			scanf("%d", &a);
			d[a % p]++;
			mx = max(mx, a);
		}
		for (int i = 0; i < 2*m; i++) {
			d[i + p] = d[i];
		}
		int ans = -1, l = 0, cn = 0;
		for (int i = 0; i <= 4 * m; i++) {
			cn += d[i];
			if (i - l >= m) {
				cn -= d[l];
				l++;
			}
			if (cn == n) {
				ans = i;
				break;
			}
		}
		if (ans == -1) {
			cout << -1 << endl;
			continue;
		}
		//cout << "_______________" << ans << endl;
		int s = mx + ((ans - mx) % p + p) % p;
		cout << s << endl;
	}
	return 0;
}

/*
9
4 4
2 3 4 5
4 3
2 3 4 5
4 3
3 4 8 9
3 3
6 2 1
1 1
1
7 5
14 34 6 25 46 7 17
6 5
40 80 99 60 90 50
6 5
64 40 50 68 70 10
2 1
1 1000000000


*/

D. Med-imize 

解析:二分+dp

使用一种不需要排序就能找到中位数的方法:

使用二分,每次判断mid是否是中位数,将数组ai>=mid的值标为1,否则标为-1,-1的个数等于1的个数时说明mid是中位数,形式地表示为sum=0时mid是中位数。

对于删除子数组操作使用dp处理:

f[i] 表示:前 i 个中剩余个数不超过 k 的最大sum。sum>=0表示mid可以更大,反之mid取的过大

注意到删除的子数组必须是连续的k个,所以:

f[i]=max(f[i-k],f[i-1]+b[i]);

又因为最后剩余的个数必须小于 k 个,所以:

if(i%k==0):f[i]=max(f[i-k],b[i]);

因为当 i%k==0 时,如果保留第 i 个和第 i-1 个,则此时前面还剩下 x 个,此时 x%k+2 一定会等于 k,不合题意。这个性质手写几个例子就能发现。

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
typedef long long LL;
//#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 5e5 + 10, M = 1e6 + 10;
int n,k;
int A[N], b[N], f[N];

bool check(int mid) {
	for (int i = 0; i < n; i++) {
		if (mid <= A[i]) {
			b[i] = 1;
		}
		else {
			b[i] = -1;
		}
	}
	f[0] = b[0];
	for (int i = 1; i < n; i++) {
		if (i % k == 0) {
			f[i] = max(b[i], f[i - k]);
		}
		else {
			f[i] = f[i - 1] + b[i];
			if (i > k) {
				f[i] = max(f[i], f[i - k]);
			}
		}
	}
	return f[n - 1] > 0;
}

signed main() {
	int T;
	cin >> T;
	while (T--) {
		scanf("%d%d", &n,&k);
		int mx = 0;
		for (int i = 0; i < n; i++) {
			scanf("%d", &A[i]);
			mx = max(mx, A[i]);
		}
		int l = 0, r = mx, ret = l;
		while (l <= r) {
			int mid = l + (r - l) / 2;
			if (check(mid)) {
				ret=mid;
				l=mid+1;
			}
			else {
				r=mid-1;
			}
		}
		printf("%d\n",ret);
	}
	return 0;
}

/*

5
4 3
3 9 9 2
5 3
3 2 5 6 4
7 1
5 9 2 6 5 4 6
8 2
7 1 2 6 8 3 4 5
4 5
3 4 5 6

*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值