Codeforces Round #732 (Div. 2)

本文解析了三个编程问题:数组间的加减操作计步、字符串偷换后的识别、奇偶位置元素保持的排序。通过算法思路和代码实现,探讨了如何高效判断和操作数组与字符串,展示了数据结构和逻辑思维在解决这类问题中的关键作用。

A AquaMoon and Two Arrays

题目大意

给两个长度为n的数组,问a数组是否能通过给一个数+1,另一个数-1操作变成数组b,如果能输出操作步数且打印方案

主要思路

如果suma == sumb那么一定能变成,用st数组记录每个ai - bi的值,所有st数组中大于0的值的和就是操作步数,然后再用两个指针一个指向st中的负数,一个指向st中的正数,输出即可

AC代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

const int N = 200010;
int n, a[N], b[N];
int st[N];

signed main(void)
{
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        int suma = 0, sumb = 0;
        int cnt = 0;
        for(int i = 0; i < n; i++) cin >> a[i], suma += a[i];
        for(int i = 0; i < n; i++)
        {
            cin >> b[i];
            st[i] = a[i] - b[i];
            sumb += b[i];
            if(st[i] > 0) cnt += st[i];
        }

        if(suma != sumb)
        {
            puts("-1");
        }
        else
        {
            int pos1 = -1, pos2 = -1;
            for(int i = 0; i < n; i++)
            {
                if(st[i] < 0 && pos1 == -1) pos1 = i;
                if(st[i] > 0 && pos2 == -1) pos2 = i;
                if(pos1 != -1 && pos2 != -1)
                {
                    break;
                }
            }
            
            cout << cnt << endl;

            while(pos1 < n || pos2 < n)
            {
                while(st[pos1] >= 0 && pos1 < n) pos1++;
                while(st[pos2] <= 0 && pos2 < n) pos2++;

                if(pos1 < n && pos2 < n && st[pos1] < 0 && st[pos2] > 0)
                {
                    cout << pos2 + 1 << ' ' << pos1 + 1 << endl;
                    st[pos1]++, st[pos2]--;
                }
            }
        }
    }
    return 0;
}

B AquaMoon and Stolen String

题目大意

给定n个长度为m的字符串,再给n-1个长度为m的字符串,其中n - 1个字符串是由n个字符串中的n-1个交换每个位置上的元素得到,问n个字符串中没有参与交换的是哪个

主要思路

统计每一列中某个字母的个数,如果某一行的所有字母在每一列中都是奇数 那么这一行就是答案

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

const int N = 100010;
int n, m;
int st[N][30];
string s[N];

signed main(void)
{
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m;
        memset(st, 0, sizeof(st));
        for(int i = 0; i < n; i++)
        {
            cin >> s[i];
            for(int j = 0; j < m; j++)
            {
                st[j][s[i][j] - 'a']++;
            }
        }
        for(int i = 0; i < n - 1; i++)
        {
            string s;
            cin >> s;
            for(int j = 0; j < m; j++)
            {
                st[j][s[j] - 'a']++;
            }
        }

        for(int i = 0; i < n; i++)
        {
            bool flag = true;
            for(int j = 0; j < m; j++)
            {
                if(st[j][s[i][j] - 'a'] % 2 == 0)
                {
                    flag = false;
                    break;
                }
            }
            if(flag)
            {
                cout << s[i] << endl;
                break;
            }
        }
    }
    return 0;
}

C AquaMoon and Strange Sort

题目大意

给定一个长度为n的数组,刚开始每个元素都指向右,每次交换相邻两个元素都会是元素指向改变,问能否给该数组排序,同时使最后所有元素还是都指向右

主要思路

每个元素都交换两次才能保证最后每个元素还是指向右边,那么开始在奇数位置的元素还在奇数位置,开始在偶数位置的元素还在偶数位置,那么我们把奇数位置元素记下,偶数元素位置元素记下,直接对原数组排序,如果奇数位置还是那些数,则说明能该边,如果奇数位置不是原来那些数,则说明不能改变

AC代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

const int N = 100010;
int n, a[N];
int f[2][N];

signed main(void)
{
    int T;
    cin >> T;
    while(T--)
    {
        memset(f, 0, sizeof(f));
        cin >> n;
        for(int i = 0; i < n; i++)
        {
            cin >> a[i];
            f[i % 2][a[i]]++;
        }

        sort(a, a + n);
        for(int i = 0; i < n; i++)
        {
            f[i % 2][a[i]]--;
        }

        bool flag = true;
        for(int i = 0; i < N; i++)
        {
            if(f[0][i] || f[1][i])
            {
                flag = false;
                break;
            }
        }

        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}

D AquaMoon and Chess

题目大意

给你一个0 1串,1只能隔一个1跳到相邻位置的0(象棋的炮), 问有多少种排列方式

主要思路

1的移动是以11为单位,因此我们可以计算出有多少个11,和计算出有多少个0,相当于n个相同的球放进m个盒子中,且允许空箱,那么答案就为C(n + m - 1, m - 1),m为1可以在0中插入的位置个数,也就是0的个数+1

不同情况组合数公式见:https://blog.youkuaiyun.com/u012720552/article/details/80961684

AC代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;

#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;

const int N = 100010, mod = 998244353;
int n;

int qmi(int a, int k, int p)  // 快速幂模板
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = res * a % p;
        a = a * a % p;
        k >>= 1;
    }
    return res;
}

int C(int a, int b, int p)  // 通过定理求组合数C(a, b)
{
    if (a < b) return 0;

    int x = 1, y = 1;  // x是分子,y是分母
    for (int i = a, j = 1; j <= b; i --, j ++ )
    {
        x = x * i % p;
        y = y * j % p;
    }

    return x * qmi(y, p - 2, p) % p;
}

int lucas(int a, int b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (int)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

signed main(void)
{
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        string s;
        cin >> s;
        int a = 0, b = 0;
        for(int i = 0; i < n; i++)
        {
            if(s[i] == '0') a++;
            else
            {
                int cnt = 0;
                while(s[i] == '1')
                {
                    cnt++;
                    i++;
                }
                b += cnt / 2;
                i--;
            }
        }
        a++;
        cout << lucas(a + b - 1, a - 1, mod) << endl;
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值