CodeCraft-22 and Codeforces Round #795 (Div. 2)

文章目录

A

思路: 任意相邻元素之和为偶数,那么这两个数定是两个偶数或者奇数,也就意味者整个序列只能有奇数或者偶数。

signed main(){
	cin >> t;
	while (t --) {
		cin >> n;
		int a = 0, b = 0;
		for (int i =  1; i <= n; i ++) {
			cin >> x;
			if (x % 2) a ++;
			else b ++;
		}
		cout << min(a, b) << endl;
	} 
	return 0;
}

B

思路:要求每个人之间换一个数,每个人只能换大于等于他的数,那么这就意味着,只能换等于他的数,因为换大于他的数,原来的那个人就只有去找更大的了,最后,一定会有一个人找不到数可以换。
每个人对于和他自己相等的数,移动一个位置即可

signed main(){
	tle
	cin >> t;
	while (t --) {
		cin >> n;
		map<int, vector<int>> mp;
		for (int i = 1; i <= n; i ++) cin >> x, mp[x].push_back(i);
		int f = 1;
		for (auto& t : mp) 
			if (t.second.size() < 2) f = 0;
			else {
				auto& p = t.second;
				int l = p.size();
				for (int i = 0; i < l; i ++)
					s[p[i]] = p[(i + 1)%l];
			}
		if (f) {
			for (int i = 1; i <= n; i ++) cout << s[i] << " ";
			cout << endl;
		} else cout << -1 << endl;
	} 
	return 0;
}

C

思路:01100 和 01010 其实没有区别,区别在于消除头和尾部的0
消除尾部的0,赚10
消除头部的0,赚1
头尾消除完就没了

signed main(){
	tle
	cin >> t;
	while (t --) {
		cin >> n >> k;
		string s;int ans = 0;
		cin >> s;
		for (int i = n - 1; i >= 0; i --) {
			if (s[i] == '1') {
				int st = i;
				if (i + k >= n - 1) {
					swap(s[i], s[n - 1]);
					k -= n - 1 - i;
					st --;
				}
				for (int j = 0; j <= st; j ++) {
					if (s[j] == '1'){
						if (k >= j) 
							swap(s[j], s[0]);
						break;
					}
				}
				break;
			}
		}
		for (int i = 0; i < n - 1; i ++) {
			if (s[i] == '1' && s[i + 1] == '1') ans += 11;
			else if(s[i] == '1' && s[i + 1] == '0') ans += 10;
			else if (s[i] == '0' && s[i + 1] == '1') ans += 1;
		}
		cout << ans << endl;
	} 
	return 0;
}

D

思路:找出一段和大于这一段的max。对于一段的和,在某一个区间内
找出以[i, r]范围内某一个点的最大前缀和去减去[l, i-1]范围内的最小的前缀和。 为保证i点为最大,我们需要找到i左边和i右边大于i的第一个数。
这个点上,可以用单调栈来求。
某一段上的最大值和最小值,可以用st表来求。

int k;
int l[N], r[N], st[N], idx;
int mins[N][31], maxs[N][31], pre[N];
signed main(){
	tle
	cin >> t;
	pre[1] = 0;
	pre[2] = 1;
	for (int i = 3; i < N; i ++) pre[i] = pre[i / 2] + 1;
	while (t --) {
		cin >> n;
		for (int i = 1; i <= n; i ++) 
			cin >> g[i], s[i] = s[i - 1] + g[i],
			mins[i][0] = maxs[i][0] = s[i];
		st[0] = 0;
		for (int i = 1, idx = 0; i <= n; i ++) {
			while(idx && g[st[idx]] <= g[i]) idx --;
			l[i] = st[idx];
			st[++ idx] = i;
		}
		st[0] = n + 1;
		for (int i = n, idx = 0; i >= 1; i --) {
			while(idx && g[st[idx]] <= g[i]) idx --;
			r[i] = st[idx];
			st[++ idx] = i;
		}
	
		for (int j = 1; (1 << j) <= n; j ++)
		for (int i = 1; i + (1 << j) - 1 <= n; i ++) {
			mins[i][j] = min(mins[i][j - 1], mins[i + (1 << (j - 1))][j - 1]);
			maxs[i][j] = max(maxs[i][j - 1], maxs[i + (1 << (j - 1))][j - 1]);
		}
		int f = 1;
		for (int i = 1; i <= n && f; i ++) {
			int zl = l[i], zr = r[i] - 1, j, a = 0, b = 1e18;
			
			j = pre[zr - i + 1];
			a = max(maxs[i][j], maxs[zr - (1 << j) + 1][j]);
			
			if (!zl) zl ++, b = 0;
			j = pre[i - zl];
			if (i != zl) 
				b = min(b, min(mins[zl][j], mins[i - (1 << j)][j]));
			
			//printf("%lld %lld | %lld %lld\n", a, b, zl, zr);
			if (g[i] < a - b) f = 0;
		}
		cout << (f ? "YES" : "NO") << endl;
	} 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值