AtCoder Beginner Contest 401 B~E
AtCoder Beginner Contest 401 B~E
B - Unauthorized(模拟)
代码
#include <iostream>
#define endl '\n'
using namespace std;
int n, m, k;
void solve() {
string op;
int n; cin >> n;
int flag = 0; // 记录当前是登录状态还是注销状态
int cnt = 0;
for (int i = 0; i < n; i++) {
cin >> op;
if (op == "login") {
flag = 1;
}
else if (op == "logout") {
flag = 0;
}
else if (op == "private") {
if (flag == 0) { // 注销状态访问私人内容
cnt++;
}
}
}
cout << cnt;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; _ = 1;
while (_--) {
solve();
}
return 0;
}
C - K-bonacci(前缀和、同余原理)
题意
- 一个长度为n+1的数组,前面k个是1,后面的数Ai就是i往前数k个数的和
思路
- 要求前面k个数的和,所以就可以搞个前缀和了,算的时候同余一下
- n<k直接输出1就行,因为连第k+1个数都没有
代码
#include <iostream>
#include <vector>
#define endl '\n'
using namespace std;
const int mod = 1e9;
int n, m, k;
void solve() {
cin >> n >> k;
if (n < k) {
cout << 1;
return;
}
vector<long long>a(n + 1);
vector <long long>sumA(n + 1);
sumA[0] = 1;
for (int i = 0; i < k; i++) {
a[i] = 1;
if (i == 0)continue;
sumA[i] = (sumA[i - 1] + a[i]) % mod;
}
a[k] = sumA[k - 1];
sumA[k] = sumA[k - 1] + a[k];
for (int i = k + 1; i <= n; i++) {
a[i] = (sumA[i - 1] - sumA[i - k - 1] + mod) % mod;
sumA[i] = (sumA[i - 1] + a[i]) % mod;
}
cout << a[n];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; _ = 1;
while (_--) {
solve();
}
return 0;
}
// n==4,k==2
// 1 1 2 3 5
D - Logical Filling(构造/模拟,思维)
题意
- 给长度为n的字符串S(只包含o . ?),把 ? 替换乘 o 或者 . 然后里面有k个o,然后o不能相邻
- 构造出来的字符串,如果问号的地方是确定是某个字符(o或者.),那就确定了,否则就还是 ?
思路
- 首先可以确定原本的字符串S当中,如果 o 周围有 ? ,那一定就填 . 因为不能是 o (会相邻)
- 可以算出来还要填demand个 o (填在 ? 的地方)
- 如何算 ? 怎么填 o
-
分段计算,对于每一个连续的问号段,问号数量为empt,那最多可以填 o 的数量provide就是
(empt + 1)/ 2,这个不相邻放置的问题还是经常遇到的
-
如果某一段问号段是奇数个问号,那填入provide个 o 的方法是固定的,如果是偶数个,那就有两种方法
- 计算完provide的总和,
- 如果provide>demand,那怎么放,完全不知道,所以剩下问号的位置都还是问号
- 如果provide==demand,那就按照前面奇偶的那里分析,来处理 ? 地方填什么(偶数段可以确定怎么放,而奇数段没法确定,所以都还是问号)
代码
#include <iostream>
#include <string>
#define endl '\n'
using namespace std;
int n, m, k;
void solve() {
cin >> n >> k;
string s;
cin >> s;
int cnt = 0;
// 首先可以确定一部分.的位置(o的相邻位置一定是.)
for (int i = 0; i < s.length(); i++) {
if (s[i] == 'o') {
if (i && s[i - 1] == '?') {
s[i - 1] = '.';
}
if (i < s.length() - 1 && s[i + 1] == '?') {
s[i + 1] = '.';
}
cnt++;
}
}
int demand = k - cnt;
// 如果o的数量已经等于k,那就把剩下的?都输出.
if (demand == 0) {
for (auto& ch : s) {
if (ch == '?')cout << ".";
else cout << ch;
}
return;
}
// 对于每一段连续的问号,如果数量是奇数,那就最多可以放(empt+1)/2个o
// 奇数的时候放法固定(前提所有能放o的位置刚刚好全部放满o)
// 如果是偶数,放法不固定,这一段问号不能确定
int provide = 0; // 最多可以放多少个o
int empt = 0; // 每一段连续的问号的数量
for (int i = 0; i < s.length(); i++) {
empt = 0;
int j = i;
for (; j < s.length(); j++) {
if (s[j] == '?') {
empt++;
}
else {
break;
}
}
i = j;
provide += (empt + 1) / 2;
}
if (provide == demand) {
for (int i = 0; i < s.length(); i++) {
empt = 0;
int j = i;
for (; j < s.length(); j++) {
if (s[j] == '?') {
empt++;
}
else {
break;
}
}
if ((empt & 1) == 1) { // 连续问号段是奇数,要确定放法
for (int k = 0; k < empt; k++) {
if ((k & 1) == 0) { // 这里是连续问号段中第奇数个问号
s[i + k] = 'o';
}
else {
s[i + k] = '.';
}
}
}
i = j;
}
}
cout << s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; _ = 1;
while (_--) {
solve();
}
return 0;
}
E - Reachable Set(并查集)
题意
- 给无向图,以1~n选一个k为最大节点,从1~k的节点都要包含,最后只能保留一个连通块,看最少删除几条边,可以连通出来,如果无解就输出-1
思路
-
枚举从小到大枚举k,然后遍历k的所有边,
-
如果有大于k的节点v,那就要删掉这个节点v,等到k枚举到v的时候,再放出来
-
如果是v<=k,那就连通
-
代码
#include <iostream>
#include <vector>
using namespace std;
#define endl '\n'
const int N = 2e5 + 5;
int n, m, cnt;
vector<int>ans, par, dele;
vector<vector<int>>adj;
int find(int x) {
if (par[x] == x)return x;
return par[x] = find(par[x]);
}
void merge(int x, int y) {
int parx = find(x);
int pary = find(y);
if (parx != pary) {
cnt--;
}
par[pary] = parx;
}
void init() {
cin >> n >> m;
par.resize(n + 1);
dele.resize(n + 1);
adj.resize((n + 1), vector<int>());
for (int i = 1; i <= n; i++) {
par[i] = i;
}
int u, v;
for (int i = 0; i < m; i++) {
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
}
void solve() {
init();
// 以1~n为最大节点,看每次最少有多少个连通块,如果最少为1,那就合法
int res = 0;
for (int k = 1; k <= n; k++) {
cnt++;
if (dele[k]) {
dele[k] = 0;
res--;
}
for (auto v : adj[k]) {
if (v > k) {
if (dele[v]) continue; // 已经不在连通块里面了
dele[v] = 1;
res++;
}
else {
if (dele[v]) {
dele[v] = 0;
res--;
}
merge(v, k);
}
}
ans.push_back((cnt == 1) ? res : -1);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int _ = 1;
//cint>>_;
while (_--) {
solve();
}
for (auto x : ans)cout << x << endl;
return 0;
}

浙公网安备 33010602011771号