Loading

AtCoder Beginner Contest 350




B - Dentist Aoki

难度: ⭐

题目大意

现在有数列1 ~ n, 现在有m次操作, 每次给出一个x, 如果x存在就是删去, 不存在就加上; 问最后数列还剩多少个;

解题思路

数据很小, 暴力就行;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 131;
typedef pair<int, int> PII;
int n, m;
int p[N], f[N];
signed main(){
    IOS;
    cin >> n >> m;
    for(int i = 1; i <= m; i++){
        int x;
        cin >> x;
        if(f[x]) n++;
        else n--;
        f[x] = !f[x];
    }
    cout << n;
	return 0;
}




C - Sort

难度: ⭐⭐

题目大意

现在有一个乱序的数列A, A由1 ~ n组成; 我可以选择两个位置并把这两个位置上的数字互换, 请问最少进行多少次这种操作可以把A变成有序的;

解题思路

也是打暴力, 用数组p[i] = x表示第i个位置上的数字是x, f[x] = i表示数字x的位置是i; 我们从1 ~ n遍历, 依序调整数字位置即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 131;
typedef pair<int, int> PII;
int n, m;
int p[N], f[N];
vector<PII> v;
signed main(){
    IOS;
    cin >> n;
    for(int i = 1; i <= n; i++){
        int x;
        cin >> x;
        p[i] = x;
        f[x] = i;
    }
    int num = 0;
    for(int i = 1; i <= n; i++){
        if(p[i] != i){
            v.push_back({i, f[i]});
            num++;
            int u = p[i];
            p[f[i]] = u;
            p[i] = i;
            f[u] = f[i];
            f[i] = i;
        }
    }
    cout << num << endl;
    for(auto x : v){
        cout << x.first << ' ' << x.second << endl;
    }
	return 0;
}




D - New Friends

难度: ⭐⭐⭐

题目大意

现在有n个人, 其中有m对朋友; 如果A和B是朋友, B和C是朋友, 但是A和C不是朋友, 那么我们就可以介绍A和C成为朋友; 并且此后就把A和C视为朋友关系; 请问我们最多可以介绍多少对人成为朋友;

解题思路

如果朋友之间用边相连的话, 题目问的就是我们可以在基础上多连多少条边; 根据题意我们发现一个连通块的里的点都可以相互成为朋友; 一个n个点的连通块最多有n * (n - 1) / 2条边, 减去原本存在的边就是我们可以连的边了; 用并查集标记连通块;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 131;
typedef pair<int, int> PII;
int n, m;
int p[N];
bool st[N];
map<int, int> mp1, mp2;
vector<int> v[N];
int find(int x){
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
signed main(){
    IOS;
    cin >> n >> m;
    for(int i = 1; i <= n; i++) p[i] = i;
    for(int i = 1; i <= m; i++){
        int a, b;
        cin >> a >> b;
        v[a].push_back(b);
        if(find(a) != find(b)){
            p[find(b)] = find(a);
        }
    }
    for(int i = 1; i <= n; i++){
        int a = find(i);
        mp1[a]++;
        mp2[a] += v[i].size();
    }
    int res = 0;
    for(auto x : mp1){
        int a = x.first, b = x.second;
        int sum = b * (b - 1) / 2 - mp2[a];
        res += sum;
    }
    cout << res;
	return 0;
}




E - Toward 0

难度: ⭐⭐⭐

题目大意

给定一个值n, 我们有两种选择
一是花费X元, 让n变成n / A(向下取整);
二是花费Y元, 扔一个骰子, 设B是骰子的点数结果, 让n变成n / B(向下取整);
请问让n变成0的最少期望花费;

解题思路

概率dp, 设dp[i]表示让i变成0的最少期望花费;
根据选择一, dp[i] = dp[i / A] + X;
然后看选择二的期望: dp[i] = dp[i] / 6 + dp[i / 2] / 6 + dp[i / 3] / 6 + dp[i / 4] / 6 + dp[i / 5] / 6 + dp[i / 6] / 6 + Y; 移项化简得dp[i] = 5 * dp[i / 2] + 5 * dp[i / 3] + 5 * dp[i / 4] + 5 * dp[i / 5] + 5 * dp[i / 6] + 6 * Y / 5;
两者取最小即可; 本题的另一难点在于n的范围在1e18; 所以要挑选出所有可能遇到的i的值拿来状态转移, 可以用dfs加记忆化搜索;

神秘代码

#include<bits/stdc++.h>
#define int unsigned long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 131;
typedef pair<int, int> PII;
int n, m, A, B, res;
int p[N];
map<int, double> dp;
map<int, int> mp;
set<int> s;
void dfs(int u){
    s.insert(u);
    mp[u] = 1;
    for(int i = 2; i <= 6; i++){
        if(u / i != 0&& mp[u / i] == 0) dfs(u / i);
    }
}
signed main(){
    cin >> n >> m >> A >> B;
    dfs(n);
    dp[0] = 0;
    while(s.size()){
        int x = *s.begin();
        if(x > n) break;
        s.erase(x);
        dp[x] = dp[x / m] + A;
        double sum = 0;
        for(int i = 2; i <= 6; i++){
            sum += dp[x / i] / 5;

        }
        sum += (6.0 * B) / 5;
        dp[x] = min(dp[x], sum);
    }
    printf("%.9lf", dp[n]);
	return 0;
}




F - Transpose

难度: ⭐⭐⭐(⭐)

题目大意

现有一个字符串S, 其由大小写字母和括号组成, 并且保证括号的用法一定合法; 现在需要对S进行以下操作, 直到S中没有括号;
首先选中S的一段子串T, 要求T的开头是'(', 末尾是')', 并且中间没有其他括号; 然后把T中的字母大小写反转, 然后把顺序倒过来; 再然后把两端的括号删去, 把中间处理完的字符串放回原位置;
已知无论操作顺序, 最后的结果都一致, 输出最后的S;

解题思路

我们可以把大小写反转和顺序翻转分开来处理; 首先我们可以根据当前字母S[i]包含于几个括号之内来判断是否需要翻转, 奇数就反转, 偶数就不反转;
而且顺序翻转因为需要O(n)来实现, 我们可以模拟一下O(n)的过程; 如果需要遇到'('且此时需要顺序翻转, 我们就要跳到对应的')'处从后往前走; 如果之后又遇到了')', 并且此时也需要顺序翻转, 那么我们就要跳到对应的'('处从前往后走; 这个过程需要用递归来实现, 而当前是从后往前还是从前往后可以根据边界l和r的大小关系来判断;

神秘代码

#include<bits/stdc++.h>
#define int unsigned long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 131;
typedef pair<int, int> PII;
int n, m;
int p[N], f[N];
string s;
void check(int l, int r){
    if(l < r){
        for(int i = l + 1; i < r; i++){
            if(p[i]){
                if(f[i] % 2) check(p[i], i);
                i = p[i];
            }
            else{
                if(isalpha(s[i])) cout << s[i];
            }
        }
    }
    else{
        for(int i = l - 1; i > r; i--){
            if(p[i]){
                if(f[i] % 2 == 0) check(p[i], i);
                i = p[i];
            }
            else{
                if(isalpha(s[i])) cout << s[i];
            }
        }
    }
    
}
signed main(){
    cin >> s;
    s = ' ' + s;
    int idx = 0;
    stack<int> st;
    for(int i = 1; i < s.size(); i++){
        if(s[i] == '('){
            idx++;
            st.push(i);
            f[i] = idx;
        }
        else if(s[i] == ')'){
            int x = st.top();
            st.pop();
            if(idx % 2) p[x] = i;
            else p[i] = x;
            f[i] = idx;
            idx--;
        }
        else{
            if(idx % 2){
                if(isupper(s[i])) s[i] += 32;
                else if(islower(s[i])) s[i] -= 32;
            }
            f[i] = idx;
        }
    }
    check(0, s.size());
	return 0;
}
posted @ 2024-04-21 18:03  mostimali  阅读(35)  评论(0编辑  收藏  举报