打完codeforces再来打打atcoder
A - Status Code
思路:就纯纯签到题,if-else判断,不说了
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int s;
cin >> s;
if (s >= 200 && s<= 299) {
cout << "Success\n";
} else {
cout << "Failure\n";
}
return 0;
}
B - Unauthorized
思路:登录登出模拟,同样是水题,跳过
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int n;
string s;
cin >> n;
int errorNum = 0;
bool login = false;
for (int i = 1; i <= n; i++) {
cin >> s;
if (s == "login") {
login = true;
}
if (s == "logout") {
login = false;
}
if (s == "private" && !login) {
errorNum++;
}
}
cout << errorNum << '\n';
return 0;
}
C - K-bonacci
思路:先打个表,突然发现1e6的数据量,貌似可以不用找规律,直接模拟。那直接来,前k个数全是1,后面每个数都是其前k个数之和,那么只要动态维护中间k个数之和即可。最后注意一下,边界。此外由于计算过程存在减法,还需要注意一下取模运算导致的负数。
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const int MOD = 1e9;
#define ll long long
int a[N];
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int n,k;
cin >> n >> k;
if (n < k) {
cout << 1 << endl;
} else {
int currentA = 0;
for (int i = 0; i <= n; i++) {
if (i < k) {
a[i] = 1;
currentA++;
} else if (i == k) {
a[i] = currentA;
} else {
currentA = (currentA - a[i - k - 1] + currentA) % MOD;
if (currentA < 0) {
currentA += MOD;
}
a[i] = currentA;
}
}
cout << currentA << endl;
}
return 0;
}
D - Logical Filling
思路:看似策略题,其实又是一个模拟题。字符串输入包含o,.,?三个字符,字符?可以随便改变为字符o或者字符.。给定字符o的数量,并要求字符o不可以并排,求最终每个位可能的字符(若字符.和字符o均可则输出字符?)。根据字符o不可并排的策略,首先将字符o周围的字符?全都换为字符.。之后判断连续字符?。针对偶数个连续?,则最多有一半数量为o,且这些o的位置不一定。针对奇数个连续?,则最多有一半还多一个数量为o,但这些o的位置一定,o与.相隔分布,需要维护一下最多和最少o的场景下?的替换策略。最后判断一下若最多或最小数量更好匹配题意,则直接输出维护的特定场景下?替换策略即可,否则仅需要将o周围的?替换为.即可
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const int MOD = 1e9;
#define ll long long
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int n, k;
string s;
cin >> n >> k >> s;
string x = s;
string xMax = s;
string xMin = s;
int countOMax = 0;
int countOMin = 0;
int agentQ = 0;
for (int i = 0; i < n; i++) {
if (s[i] == '?') {
if ((i - 1 >= 0 && s[i - 1] == 'o') || (i + 1 < n && s[i + 1] == 'o')) {
x[i] = '.';
xMax[i] = '.';
xMin[i] = '.';
} else {
agentQ++;
xMin[i] = '.';
}
} else {
if (agentQ > 0) {
if (agentQ % 2 == 0) {
countOMax += agentQ / 2;
agentQ = 0;
} else {
countOMax = countOMax + agentQ / 2 + 1;
int nowPos = i - 1;
while (agentQ > 0) {
if (x[nowPos] == '?') {
if (agentQ % 2 != 0) {
xMax[nowPos] = 'o';
} else {
xMax[nowPos] = '.';
}
agentQ--;
}
nowPos--;
}
}
}
if (s[i] == 'o') {
countOMax++;
countOMin++;
}
}
}
if (agentQ > 0) {
if (agentQ % 2 == 0) {
countOMax += agentQ / 2;
} else {
countOMax = countOMax + agentQ / 2 + 1;
int nowPos = n - 1;
while (agentQ > 0) {
if (x[nowPos] == '?') {
if (agentQ % 2 != 0) {
xMax[nowPos] = 'o';
} else {
xMax[nowPos] = '.';
}
agentQ--;
}
nowPos--;
}
}
}
if (countOMax == k) {
cout << xMax << '\n';
} else if (countOMin == k) {
cout << xMin << '\n';
} else {
cout << x << '\n';
}
return 0;
}
E - Reachable Set
思路:图论题,给定一个无向图,针对每一个有序节点k,判断需要至少删除多少个节点,能使节点1仅可达前k个节点。由于节点有序,不如直接将无线图转化为从小节点指向大节点的有向图。
这题主要要解两个问题,一是删除节点数量问题,二是可达性问题。删除节点数量其实倒是很容易判断。针对每个节点,将其后续节点全都删掉,即可断连。每次针对下个节点,再将下个节点加回,并将下个节点的后续节点删掉即可。维护一下删除的节点,即可知道所需删除的数量。而针对可达性问题就会比较麻烦。要判断前k个节点是否连通,连通性问题毫无疑问想到并查集。首先先把并查集的板子打上。但是肯定不能针对每个节点都一次遍历所有前k个节点,就需要剪枝了。首先第一步,不难发现,如果每次要遍历的节点在待删除列表里,那么其一定是可以连通的,就不需要再进行连通性判断了。那么只需要单独维护一下需要特殊判断的节点列表。此外,由于待删除列表存在很多添加和删除的操作,因此用数组来维护判断节点是否需要删除,然后专门记个数即可。由于前面的节点一定会先于后面的节点进行操作,因此更新删除节点基于点的后续节点即可进行操作。而判断连通性时,增加的边也只需要关注前序节点即可,因为后续节点肯定当前是不联通的。由此,整个图可以维护成两个分别基于前序和后序的领接表。最后一点剪枝就是判断节点联通性的时候,当某个节点判断不连通时,可以短路掉后续要判断的节点,避免重复无效判定。
/*
Author Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
#define ll long long
vector<int> e[N];
vector<int> de[N];
int pre[N];
bool deletedV[N];
int findx(int k) {
if (k != pre[k]) {
pre[k] = findx(pre[k]);
}
return pre[k];
}
void unionx(int a, int b) {
int aa = findx(a);
int bb = findx(b);
if (aa > bb) {
pre[aa] = bb;
} else if (aa < bb) {
pre[bb] = aa;
}
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
de[v].push_back(u);
}
for (int i = 1; i <= n; i++) {
pre[i] = i;
}
set<int> toDeleteV;
deletedV[1] = true;
int deletedCount = 1;
for (int i = 1; i <= n; i++) {
if (deletedV[i]) {
deletedV[i] = false;
deletedCount--;
} else {
toDeleteV.insert(i);
}
const int eCount = e[i].size();
for (int j = 0; j < eCount; j++) {
if (deletedV[e[i][j]]) {
continue;
}
deletedV[e[i][j]] = true;
deletedCount++;
}
const int deCount = de[i].size();
for (int j = 0; j < deCount; j++) {
unionx(i, de[i][j]);
}
vector<int> toDeleteVdeleted;
for (int needDeleteV: toDeleteV) {
if (findx(1) == findx(needDeleteV)) {
toDeleteVdeleted.push_back(needDeleteV);
} else {
break;
}
}
for (int needDeleteV: toDeleteVdeleted) {
toDeleteV.erase(needDeleteV);
}
if (toDeleteV.empty()) {
cout << deletedCount << "\n";
} else {
cout << "-1\n";
}
}
return 0;
}