Codeforces Global Round 17

本文分享了四篇关于算法竞赛中不同题目类型的解题思路,包括AntiLight's Cell Guessing的思维判断,Kalindrome Array的双指针搜索技巧,KeshiIsThrowingaParty的二分优化,以及NotQuiteLee中数字和的优化策略。通过实例解析展示了信息技术在解决复杂问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. Anti Light’s Cell Guessing

AC(思维)

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    scanf("%d", &t);
    while (t -- ) {
    	int n, m;
    	scanf("%d%d", &n, &m);
    	if (n == 1 && m != 1) cout << 1 << endl;
    	else if (m == 1 && n != 1) cout << 1 << endl;
    	else if (n == 1 && m == 1) cout << 0 << endl;
    	else cout << 2 << endl;
	}
	return 0;
}

B. Kalindrome Array

思路

  • 双指针暴搜,忘记初始化,我也是佛了
#include <bits/stdc++.h>
using namespace std;
#define PB push_back
typedef vector<int> VI;
VI a;
int main() {
    int t;
    scanf("%d", &t);
    while (t -- ) {
    	a.clear();
    	int n;
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i ++ ) {
    		int tmp;
    		scanf("%d", &tmp);
    		a.PB(tmp);
		}
		bool ok = 1;
		int num1, num2;
		for (int i = 0; i < n; i ++ )
			if (a[i] != a[n - i - 1]) {
				ok = 0;
				num1 = a[i];
				num2 = a[n - i - 1];
				break;
			}
		if (ok) {
			printf("YES\n");
			continue;
		}
		ok = 1;
		for (int i = 0, j = n - 1; i < j; ) {
			if (a[i] == a[j]) {
				i ++, j --;
			} else if (a[i] == num1) {
				while (a[i] != a[j] && a[i] == num1 && i < j) i ++;
				if (a[i] != a[j]) {
					ok = 0;
					break;
				} 
			} else if (a[j] == num1) {
				while (a[i] != a[j] && a[j] == num1 && i < j) j --;
				if (a[i] != a[j]) {
					ok = 0;
					break;
				}
			} else {
				ok = 0;
				break;
			}
		}
		if (ok) {
			printf("YES\n");
			continue;
		}
		ok = 1;
		for (int i = 0, j = n - 1; i < j; ) {
			if (a[i] == a[j]) {
				i ++, j --;
			} else if (a[i] == num2) {
				while (a[i] != a[j] && a[i] == num2 && i < j) i ++;
				if (a[i] != a[j]) {
					ok = 0;
					break;
				} 
			} else if (a[j] == num2) {
				while (a[i] != a[j] && a[j] == num2 && i < j) j --;
				if (a[i] != a[j]) {
					ok = 0;
					break;
				}
			} else {
				ok = 0;
				break;
			}
		}
		if (ok) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

C. Keshi Is Throwing a Party

思路

  • 看数据量就是 O ( n l o g n ) O(nlogn) O(nlogn),想到二分。二分答案,然后对于 m i d mid mid 来说,a[i] >= mid - i && b[i] >= i - 1
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N], b[N];
int n;
bool check(int mid) {
	int cnt = mid;
	int up = mid - 1, down = 0;
	for (int i = 1; i <= n; i ++ ) {
		if (a[i] >= up && b[i] >= down) {
			up --, down ++;
			cnt --;
			if (cnt == 0) break;
		}
	}
	bool ok = 1;
	if (cnt == 0) ok = 1;
	else ok = 0;
	return ok;
}
int main() {
    int t;
    scanf("%d", &t);
    while (t -- ) {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i ++ )
			scanf("%d%d", a + i, b + i);
		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;
	}
	return 0;
}

D. Not Quite Lee

思路

  • 首先对于任意一个数 x x x,他的和是 x ∗ ( x + 1 ) 2 \displaystyle \frac{x * (x + 1)}{2} 2x(x+1)
  • 对于 a 1 , a 2 , a 3 , . . . , a n a_1, a_2, a_3, ..., a_n a1,a2,a3,...,an 来说,他们的和 s u m = sum = sum= a 1 ∗ ( a 1 + 1 ) 2 \displaystyle \frac{a_1 * (a_1 + 1)}{2} 2a1(a1+1) + + + a 2 ∗ ( a 2 + 1 ) 2 \displaystyle \frac{a_2 * (a_2 + 1)}{2} 2a2(a2+1) + . . . + + ...+ +...+ a n ∗ ( a n + 1 ) 2 \displaystyle \frac{a_n * (a_n + 1)}{2} 2an(an+1),他们的和可以变化的最小间距是 g c d ( a 1 , a 2 , a 3 , . . . , a n ) gcd(a_1, a_2, a_3, ..., a_n) gcd(a1,a2,a3,...,an) (显然,不会证明)
  • 那么我要使 s u m = 0 sum = 0 sum=0,条件就是 s u m ∣ g c d sum | gcd sumgcd
  • 奇数很好处理,奇数和偶数凑一起, g c d = 1 gcd = 1 gcd=1,不用管奇数了
  • 偶数的就是二进制的最小位
  • 举个例子 x x x 的最小二进制位在 i i i 位上, x ∗ ( x + 1 ) 2 \displaystyle \frac{x * (x + 1)}{2} 2x(x+1) 肯定不能整除 2 i 2 ^ i 2i,如果是偶数个 x x x 就可以,如果最小二进制位为 i i i 个数为 n u m num num 个,那么他们组成的奇数方案数为 2 n u m − 1 2^{num - 1} 2num1 个,他们组成的偶数方案数为 2 n u m − 1 2^{num - 1} 2num1 个,我们不用考虑最小二进制在 i + 1 i + 1 i+1 上的 x 1 x_1 x1,因为他们的和 x 1 ∗ ( x 1 + 1 ) 2 \displaystyle \frac{x_1 * (x_1 + 1)}{2} 2x1(x1+1) 肯定可以被 2 i 2 ^ i 2i 整除
  • 我们先列出最多多少种方案, 2 n − 1 2 ^ n - 1 2n1 种,减去不合适的方案数,二进制位为 i i i 个数为 n u m num num 个,他们组成的奇数方案数为 2 n u m − 1 2^{num - 1} 2num1 个,同时他们和任何二进制位比 i i i 高的任何数都不能成方案
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int num[40], base[N];
int main() {    
	base[0] = 1;
    int n;
    scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) 
		base[i] = (base[i - 1] * 2) % mod;
    for (int i = 1; i <= n; i ++ ) {
    	int tmp;
    	scanf("%d", &tmp);
    	int cnt = 0;
    	while (tmp % 2 == 0) {
    		tmp /= 2;
    		cnt ++;
		}
		num[cnt] ++;
	}
	int sum = 0;
	LL ans = base[n] - 1;
    for (int i = 32; i; i -- ) {
    	if (!num[i]) continue;
    	sum += num[i];
    	ans = (ans - base[sum - 1] + mod) % mod;
	}
	cout << ans << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值