Codeforces Round #744 (Div. 3)

这篇博客介绍了ACasimir'sStringSolitaire问题的解决方案,涉及字符串删除操作的游戏策略。关键点在于判断B字符数量是否等于A和C的总和,提供了解题的AC代码示例。

A Casimir’s String Solitaire

题目大意

给定一个字符串和两种操作

  • 删除任意位置A和B
  • 删除任意位置B和C

问能否将全部字母删除

题目大意

判断B数量是否等于A+C的数量即可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m, a[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        string s;
        cin >> s;
        int a = 0, b = 0, c = 0;
        for(int i = 0; i < s.size(); i++)
        {
            if(s[i] == 'A') a++;
            else if(s[i] == 'B') b++;
            else c++;
        }
        if(a + c == b) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

B Shifting Sort

题目大意

给定一个长度为n的数组,问能否通过对某一个区间的操作使他变成递增的,问操作的步骤,操作不超过n次

主要思路

先排序,遍历排序后数组,对于每一个数在原数组中找到对应的然后将它移动到该位置即可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m, a[N], b[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
            cin >> a[i];
            b[i] = a[i];
        }
        
        sort(a + 1, a + 1 + n);
        vector<int> ans1, ans2, ans3;
        
        for(int i = 1; i <= n; i++)
        {
            int t;
            if(a[i] == b[i]) continue;
            for(int j = i + 1; j <= n; j++)
            {
                if(a[i] == b[j])
                {
                    ans1.push_back(i);
                    ans2.push_back(j);
                    ans3.push_back(j - i);
                    t = j;
                    break;
                }
            }
            for(int j = t - 1; j >= i; j--)
            {
                b[j + 1] = b[j];
            }
            b[i] = a[i];
        }
        cout << ans1.size() << endl;
        for(int i = 0; i < ans1.size(); i++)
        {
            cout << ans1[i] << ' ' << ans2[i] << ' ' << ans3[i] << endl;
        }
    }
    return 0;
}
C Ticks
题目大意

每一个*都会往左上右上延申,且每一个点最小延申k,问这个图能否通过延申得到

主要思路

遍历每一个*,如果他能延申,就将延伸到最长的路径都标记,最后判断是不是所有 *都被标记即可

AC代码

(学jls的写法)

#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 110, mod = 998244353;
int n, m, k;
char mp[N][N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m >> k;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                cin >> mp[i][j];
            }
        }
        
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(mp[i][j] == '.') continue;
                int d = 0;
                while(i - d >= 1 && j - d >= 1 && j + d <= m && mp[i - d][j - d] != '.' && mp[i - d][j + d] != '.') d++;
                d--;
                
                if(d >= k)
                {
                    for(int l = 0; l <= d; l++)
                    {
                        mp[i - l][j - l] = 'X';
                        mp[i - l][j + l] = 'X';
                    }
                }
            }
        }
        
        bool flag = true;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                if(mp[i][j] == '*') flag = false;
        if(flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}
D Productive Meeting
题目大意

给定一个长度为n的数组,每次你能任选两个数让他们同时-1,问最多的操作次数

主要思路

由于a[i]总和最大为1e5,我们定义一个优先队列,每次取最大的两个数让他们同时-1再放回优先队列中即可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m, a[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        priority_queue<pair<int, int>> q;
        vector<pair<int, int>> ans;
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
            int x;
            cin >> x;
            if(x) q.push({x, i});
        }
        
        while(q.size() > 1)
        {
            auto [a1, pos1] = q.top();
            q.pop();
            auto [a2, pos2] = q.top();
            q.pop();
            
            ans.push_back({min(pos1, pos2), max(pos1, pos2)});
            if(a1 > 1) q.push({a1 - 1, pos1});
            if(a2 > 1) q.push({a2 - 1, pos2});
        }
        
        cout << ans.size() << endl;
        for(auto i : ans)
        {
            cout << i.x << ' ' << i.y << endl;
        }
    }
    return 0;
}

E1 Permutation Minimization by Deque

题目大意

给定一个长度为n的序列,每次往双端队列中插入一个数,问字典序最小的序列是什么

主要思路

比双端队列第一个数小就放前面,比第一个数大就放后面

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m, a[N], b[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        deque<int> q;
        for(int i = 1; i <= n; i++) cin >> a[i];
        q.push_front(a[1]);
        for(int i = 2; i <= n; i++)
        {
            if(a[i] >= q.front()) q.push_back(a[i]);
            else q.push_front(a[i]);
        }
        
        for(auto i : q)
        {
            cout << i << ' ';
        }
        cout << endl;
    }
    return 0;
}

E2 Array Optimization by Deque

题目大意

给定一个长度为n的序列,每次往双端队列中插入一个数,问序列逆序对个数最小是多少

主要思路

考虑每一次放数时会生成的逆序对数量,加入当前序列中比放入的数x大的数的个数为cnt1,比放入的数x小的数的个数为cnt2,那么我们肯定选择生成逆序对最小的放法。

  • cnt1 >= cnt2,x放在双端队列末尾
  • 否则,x放在双端队列开头

接下来考虑如何判断双端队列中大于x和小于x的数的个数

我们先把输入的数组排序+离散化,然后每个数都有确定的下标,于是我们用树状数组维护每个数的出现次数即可,例如插入一个数x,我们在数组中二分查找到x的下标,在树状数组中+1即可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m, b[N];
int tr[N];
vector<int> a;

int lowbit(int x)  // 返回末尾的1
{
    return x & -x;
}

void add(int x, int c)
{
    for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}

int sum(int x)
{
    int res = 0;
    for(int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

int find(int x)
{
    return lower_bound(a.begin(), a.end(), x) - a.begin();
}

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        a.clear();
        int res = 0;
        
        cin >> n;
        for(int i = 0; i < n; i++)
        {
            int x;
            cin >> x;
            a.push_back(x), b[i] = x;
        }
        
        sort(a.begin(), a.end());
        a.erase(unique(a.begin(), a.end()), a.end());
        
        for(int i = 0; i < n; i++)
        {
            int t = find(b[i]) + 1;
            int cnt1 = sum(a.size()) - sum(t);
            int cnt2 = sum(t - 1);
            if(cnt1 >= cnt2) res += cnt2;
            else res += cnt1;
            add(t, 1);
        }
        
        for(int i = 0; i < n; i++)
        {
            int t = find(b[i]) + 1;
            add(t, -1);
        }
        cout << res << endl;
    }
    return 0;
}

F Array Stabilization (AND version)

题目大意

我们每次让该数组最后d位放到数组前面,也就是所有的i变成(i + d) % n,然后让变化后的数组每一个元素&变化前的数组,求该数组全0时的操作次数

主要思路

0不会对答案造成影响,我们只需判断每一位1需要多少次操作能变成0即可。

然后我们bfs遍历这个序列判断出每个点的最小步数, 求最小步数的最大值即可。

我们先把0放进队列,然后更新他能到的位置的最小值,如果该位置被更新然后再将该位置放进队列,相当于bfs的操作

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> P;
const int N = 1000010, mod = 998244353;
int n, m, k, a[N];
int dist[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        memset(dist, 0x3f, sizeof(dist));
        cin >> n >> k;
        for(int i = 0; i < n; i++) cin >> a[i];
        
        priority_queue<int, vector<int>, greater<int>> q;
        
        for(int i = 0; i < n; i++)
        {
            if(!a[i])
            {
                q.push(i);
                dist[i] = 0;
            }
        }
        
        while(q.size())
        {
            int pos = q.top();
            q.pop();
            if(dist[pos] + 1 < dist[(pos + k) % n])
            {
                q.push((pos + k) % n);
                dist[(pos + k) % n] = dist[pos] + 1;
            }
        }
        
        int mx = 0;
        for(int i = 0; i < n; i++)
        {
            mx = max(mx, dist[i]);
        }

        if(mx == 0x3f3f3f3f3f3f3f3f) cout << -1 << endl;
        else cout << mx << endl;
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值