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;
}
}
}