Codeforces Round 1017 (Div. 4) A~F

Codeforces Round 1017 (Div. 4) A~F

A. Trippi Troppi

题意&思路

  • 输出每个字符串的第一个数字

代码

#include <iostream>
#include <string>
#define endl '\n'
using namespace std;

void solve() {
	string s1, s2, s3;
	cin >> s1 >> s2 >> s3;
	cout << s1[0] << s2[0] << s3[0] << endl;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

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

B. Bobritto Bandito

题意

  • 从0点开始感染,每次感染左边或者右边的,最终感染的区间是[l,r]

思路

  • 当前是第n个状态,要找到第m个状态,也就是要倒退n-m天,那就是被感染的房子数量要减少n-m个
  • 我是先让右边倒退(题意应该是每次感染左右都是随机的,所以顺序无所谓),右边最多可以倒退r次(到了0之后就不能再倒退了)
  • 也就是右边最多取消感染r个房子,那就看r和n-m的关系,如果r>n-m,那就只要处理右边,否则剩下的(n-m)-r天,留给左边处理

代码

#include <iostream>
#define endl '\n'
using namespace std;

void solve() {
	int n, m, l, r;
	cin >> n >> m >> l >> r;
	int ri = min(n - m, r);
	if (ri == r) {
		l += ((n - m) - ri);
	}
	cout << l << " " << r - ri << endl;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

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

C. Brr Brrr Patapim

题意

  • 给一个二维数组,然后根据二维数组求一个序列
  • 二维数组里面的Gi,j代表了序列里第 i+j 个数字

思路

  • 序列就是从1到2n每个数字出现一次,二维数组会告诉i+j位置的数字,i+j的范围是[2,2n]
  • 所以就是序列的第一个数字没有告诉,其他位置的数字都告诉了,那么就搞一个vis数组,标记从1到2n,里面哪个数字出现了,哪个数字没有出现,没有出现那个就是第一个位置的数字
  • 具体就是先处理二维数组里的数字,填到序列数组的对应位置,输出的时候先输出第一个位置的数字,然后再从第二个位置开始输出序列数组

代码

#include <iostream>
#include <cstring>
#include <vector>
#define endl '\n'
using namespace std;

int map[805][805];
int vis[805];
void solve() {
	memset(map, 0, sizeof(map));
	memset(vis, 0, sizeof(vis));
	int n; cin >> n;
	vector<int>v(2*n+5);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> v[i + j];
			vis[v[i + j]] = 1;
		}
	}
	for (int i = 1; i <= 2 * n; i++) {
		if (!vis[i]) {
			cout << i << " ";
			break;
		}
	}
	for (int i = 2; i <= 2 * n; i++) {
		cout << v[i] << " ";
	}
	cout << endl;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

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

D. Tung Tung Sahur

题意

  • 给定两个字符串p、s,都只包含LR,p中的L跟R被敲击一次,可能出现一个L,也可能出现两个L(R同样),就问根据p这个敲击顺序,可不可能听到s这样的声音

思路

  • 记录p和s中,L和R每个连续段的长度,让L和R的每个段对应上(前提是p和s的第一个字符要一样),假设p上每一段连续段的L(或者R)数量是i,那p这一段可能产生的声音就是 [i,2*i]个 L(或者R),如果s中对应那一段的数量,不在这个范围,那就不对

代码

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#define endl '\n'
using namespace std;
vector<int>ans;

void solve() {
	string p, s; cin >> p >> s;
	if (p[0] != s[0]) {
		ans.push_back(0);
		return;
	}
    
	vector<int>vp, vs;
	int cnt = 1;
	for (int i = 1; i < p.length(); i++) {
		if (p[i - 1] == p[i]) {
			cnt++;
		}
		else {
			vp.push_back(cnt);
			cnt = 1;
		}
	}
	vp.push_back(cnt);
    
	cnt = 1;
	for (int i = 1; i < s.length(); i++) {
		if (s[i - 1] == s[i]) {
			cnt++;
		}
		else {
			vs.push_back(cnt);
			cnt = 1;
		}
	}
	vs.push_back(cnt);
    
    // 对应不上
	if (vp.size() != vs.size()) {
		ans.push_back(0);
		return;
	}
    
    // 可以打印看一下
	//for (auto x : vp) {
	//	cout << x << " ";
	//}
	//cout << endl;
	//for (auto x : vs) {
	//	cout << x << " ";
	//}
	//cout << endl;
    
	for (int i = 0; i < vs.size(); i++) {
		if (vp[i] * 2 < vs[i] || vp[i] > vs[i]) {
			ans.push_back(0);
			return;
		}
	}
	ans.push_back(1);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int _; cin >> _;
	while (_--) {
		solve();
	}
	for (auto x : ans) {
		cout << ((x) ? "YES" : "NO") << endl;
	}
	return 0;
}

E. Boneca Ambalabu

题意

  • 给一个数组,然后每次拿出其中一个ak,求 (ak⊕a1)+(ak⊕a2)+…+(ak⊕an) ,找到最大的结果

思路

  • 第一次写这种肯定很容易就可以想到枚举k,然后再计算n次得到结果,但就是O(n2)会超时
  • 所以就想异或的计算,如果取出来的 ak 的第 j个位置是0,取出每一个ai的第j个位置要是1,这时候才产生贡献,因为异或是(不进位相加)嘛,所以可以这时候可以不用枚举ai,可以提前算出这n个数字里面,第j个位置是1的有多少个,把计算这一位的时间从O(n)变成O(1)了,那就不会超时,如果取出来的 ak 的第 j个位置是1,也同理,其他数字对应位置是0的数量就是n-对应位置是1的数量
  • 贡献计算是把枚举的ak按位拆开,逐位看贡献

代码

#include <iostream>
#include <vector>
#include <algorithm>
#define endl '\n'
using namespace std;
vector<long long>ans;
int n;
void solve() {
	cin >> n;
	vector<int>cnt(31, 0);				// 每一位上1出现的次数
	vector<long long>a(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		for (int j = 0; j < 31; j++) {
			if ((a[i] >> j) & 1) {		// 把第j个位置的数移到最后一位,和1与运算
				cnt[j]++;
			}
		}
	}
	long long res = 0, sum = 0;
	for (int k = 1; k <= n; k++) {		// 枚举ak,外面是O(n)
		sum = 0;
		for (int j = 0; j < 31; j++) {	// 枚举位置
			if ((a[k] >> j) & 1) {		// 是1,那就看对应位置是0的数量
				sum += 1ll * (n - cnt[j]) * (1ll << j);
			}
			else {
				sum += 1ll * cnt[j] * (1ll << j);
			}
		}
		res = max(res, sum);
	}
	ans.push_back(res);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int _; cin >> _;
	while (_--) {
		solve();
	}
	for (auto x : ans) {
		cout << x << endl;
	}
	return 0;
}

F. Trulimero Trulicina

题意

  • n*m的网格,把1,2,3,4...... k ,每个数字都填入相同的次数

思路

  • 一开始试一下把1,2,3,4...... k,1,2,3,4...... k,....... 按顺序填进去

    样例那个3 4 6 就变成

    1 2 3

    4 5 6

    1 2 3

    4 5 6

    发现符合题意,那就可以按照这样构造

    num从0开始,每次输出num % k + 1,然后num++,就可以有这样的效果

  • 但是第一个样例2 2 2 会变成

    1 2

    1 2

    因为这时候m%k==0了,

    看个大一点的样例3 4 4

    1 2 3 4

    1 2 3 4

    1 2 3 4

    或者k≠m的:3 4 2

    1 2 1 2

    1 2 1 2

    1 2 1 2

    发现每一行会跟上面或者下面的数字相同,所以要试一下错位,在每一行开始的时候,让num先+1,感觉可以理解为,第一行的num从1开始,第二行的num从2开始……

代码

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#define endl '\n'
using namespace std;
int n, m, k;
void solve() {
	cin >> n >> m >> k;
	bool flag = false;
	if (m % k == 0)flag = true;
	int num = 0;
	for (int i = 1; i <= n; i++) {
		if (flag)num++;
		for (int j = 1; j <= m; j++) {
			cout << (num++ % k + 1) << " ";
		}
		cout << endl;
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int _; cin >> _;
	while (_--) {
		solve();
	}
	return 0;
}
posted @ 2025-04-14 12:03  zombieee  阅读(84)  评论(0)    收藏  举报