AT coder 380

A

题目:六个数字中是否满足1有1个,2有两个,三有三个;

模拟

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
map<int, int> ma;
int n,flag;

void ac() {
	cin >> n;

	while (n) {
		int cnt = n % 10;
		ma[cnt]++;
		n /= 10;
	}
	if (ma[1]==1 && ma[2]== 2 && ma[3] == 3) cout << "Yes" << endl;
	else cout << "No" << endl;
}

B

题目:长度为N的串,首项为“|”,之后是根据数组A的每一项的数字添加对应得*号之后添加一个‘|’,求A数组;

模拟

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
map<int, int> ma;
int n,flag;
string s;
void ac() {
	cin >> s;
	int ans = 0;
	for (int i = 1; i < s.size(); i++) {
		if (s[i] == '-') {
			ans++;
		}
		if (s[i] == '|') {
			cout << ans << " ";
			ans = 0;
		}
	}
}

C

题目:给定一个01字符串,连续得1组成一个块,输出将m块字符移动到n块字符后的字符串

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
map<int, int> ma;
int n,k;
string s;
void ac() {
	cin >> n >> k >> s;
	int l1=0,l = 0, r = 0, cnt = 0,flag=0;
	for (int i = 0; i < n; i++) {
		if (s[i] == '1' && !flag) {
			cnt++;//记录块数
			if (cnt == k) {//找到了第m块
				l = i;
				break;
			}
			flag = 1;
		}
		if (s[i] == '0' && flag) {
			flag = 0;
			if (cnt == k - 1) {//找到了第n块;
				l1 = i;
			}
		}
	}
	cnt = l - l1;//n块结尾到m块开头得距离;
	for (int i = l; i < n; i++) {
		if (s[i] == '0') break;
		else {
			swap(s[i], s[i - cnt]);//交换字符(距离与cnt相同,直到m块结尾)
		}
	}
	cout << s;
}

D

题目:给定一个字符串S,将其大小写反转得到字符串T,将他加入S后面得到新的字符串S,再重复这个步骤10^100次,问第i个字符是什么

分析:通过模拟字符串步骤发现,在原字符串大小为一块,初始为0,在块数的二进制中1的个数为偶,是原字符串,反之是反转后的字符串,所以只用找出i位于哪个块中即可得到该处字符的答案;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
string s;
ll q,k;

ll sum1(ll x) {//找二进制1的个数
	ll res = 0;
	while(x) {
		if (x % 2 == 1) {
			res++;
		}
		x /= 2;
	}
	return res;
}

void ac() {
	cin >> s >> q;
	ll cnt = s.size();
	while (q--) {
		cin >> k;
		k--;
		ll c = k % cnt;//找出k位于原字符串的位置
		ll wei = 0;
		//cout << c<<" " << s[c] << endl;
		if (k >= cnt) 
			wei = k / cnt;//找到k在哪个字符串块里;
		ll x = sum1(wei);
		//cout << x << endl;
		if (x%2==0) {
			cout << s[c] << " ";
		}
		else {
			if (s[c] >= 'a' && s[c] <= 'z') {
				printf("%c ", s[c] - 'a' + 'A');
			}
			else if (s[c] >= 'A' && s[c] <= 'Z') {
				printf("%c ", s[c] - 'A' + 'a');
			}
		}
	}
}

E

题目:一行有N个单元格i与i+1相邻,i被涂上第i种颜色,有两种操作1.(1 x c)将以下单元格重新涂成颜色c:通过重复移动到与当前单元格相同颜色的相邻单元格,从单元格x到达的所有可到达单元格(相邻的块才能颜色相同可以合并为一个块,被一起染色)2.(2 c)输出c颜色的块数;

分析:并查集合并,考虑合并的格子是否相邻,相邻则合并为一个块,一起变色

ll n, q, f[N], ans[N],C[N],si[N],a, x, c;

ll find(ll x) {
	return f[x] == x ? x : f[x] = find(f[x]);
}
void marge(ll x, ll y) {
	ll fx = find(x), fy = find(y);
	if (fx == fy) return;
	if (fx > fy)swap(fx, fy);//保证是小的数是根节点
	f[fy] = fx;
	si[fx] += si[fy];
}

void ac() {
	cin >> n >> q;
	for (int i = 1; i <= n; i++) ans[i] = 1,f[i]=i,C[i]=i,si[i]=1;//ans记录第i种颜色的块数,f:并查集合并数组,si:记录合并后的块数,C:颜色
	while (q--) {
		cin >> a;
		if (a == 1) {
			cin >> x >> c;
			x = find(f[x]);//找到根节点
			ans[C[x]] -= si[x];//根节点块数减去将被染色的块
			ans[c] += si[x];
			C[x] = c;//该点变色
			if (C[find(x + si[x])] == c) marge(x, x + si[x]);//该块的与后面的块相邻
			if (C[find(x - 1)] == c) marge(x - 1, x);//与前面相邻
		}
		else {
			cin >> c;
			cout << ans[c] << endl;
		}
	}
}
posted @ 2024-11-22 11:41  27hhhh  阅读(4)  评论(0编辑  收藏  举报