Codeforces Round #732 (Div. 2)(A~D)

Codeforces Round #732 (Div. 2)

具体题目可查看网站——传送门

A、AquaMoon and Two Arrays(看来这次的主角是AquaMoon)

——
在这里插入图片描述
在这里插入图片描述
题意:给出两个长度为n的数组a和b,对a数组进行一系列的操作,问能否将a数组变为b数组,若不能输出-1,若能,则输出操作次数和具体操作方式(有多种操作方式的情况下任选一种输出);
一系列操作包括:对于 a1,a2,…,an,任取一个ai和aj(1≤i,j≤n),将ai-1,aj+1,若i和j相等则操作无意义;

解题思路:先看时空间限定,标准的1s,256m;再看数据范围,t,n,ai,bi都是100以内,常规做法不用考虑超时问题。对于每一次操作将ai-1,bi+1;整个数组的总和sum不变,换言之要将数组a变为数组b,则数组a的总和要等于数组b的总和,若总和不相等则a无法变换到b,换言之总和相等a一定能变到b。若能够变换,题目要求输出的操作次数小于100,且保证一定有一个小于100的操作方法。此时就需要求最小操作次数。

题解
1、先记录数组a的总和sum和数组b的总和res,若sum!=res,输出-1;
2、若相等,对于1~n每一个ai,求得其与bi的差值ans,ans为正则第i个位置需要减少ans,ans为负表示第i个位置要加上ans,再用两个容器存储要减去和加上的位置(这里建议用vector存),操作数就是容器的容量;

#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
#include <unordered_map>
 
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 100005;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
 
int a[105];
int b[105];
 
int main()
{
    //ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);
    int t;
    scanf("%d", &t);
    while(t--){
        vector<int>x, y;
        int n;
        scanf("%d", &n);
        int ans = 0;
        int res = 0;
        for(int i = 1; i<=n; i++){
            scanf("%d", &a[i]);
            ans+=a[i];
        }
        for(int i = 1; i<=n; i++){
            scanf("%d", &b[i]);
            res+=b[i];
        }
        if(ans!=res){
            puts("-1");
        }
        else{
            for(int i = 1; i<=n; i++){
                if(a[i]>b[i]){
                    int num = a[i]-b[i];
                    while(num--)x.push_back(i);
                }
                else if(b[i]>a[i]){
                    int num = b[i] - a[i];
                    while(num--) y.push_back(i);
                }
            }
            int len = x.size();
            printf("%d\n", len);
            for(int i = 0; i<len; i++){
                printf("%d %d\n", x[i], y[i]);
            }
        }
    }
    return 0;
}

——

B、AquaMoon and Stolen String

——
在这里插入图片描述
在这里插入图片描述
题意:给出n个长度为m字符串(n为奇数),除了一个字符串s其他的字符串都有一个唯一的与其对应的字符串,现在将除s以外的字符串与他们的对应串任意取k位进行交换(0<=k<=m),给出最初的n个字符串和交换后的n-1个字符串,求没有对应串的字符串s;

解题思路:1e5的数据范围,保证每个样例n*m不超过1e5,串中只包含小写字母;对于n个字符串的第i位,无论怎么变化,这n个字符是固定的,直接开一个桶去存储,经过加减操作后看桶内还剩下的字符组成的字符串就是所求的字符串s;

题解:开一个大小[1e5][26]的二维数组做桶存储字符,读进前n个字符串时对每一位加上该字符,读进后n-1个字符串时从桶里减去该位上的字符,最后把桶里每一位仅有的一个字符输出,组成的字符串即为所求;

#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
#include <unordered_map>
 
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 100005;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
 
int a[N][26];//存储第j位上的小写字符的数量
 
int main()
{
    // ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);
    int t;
    scanf("%d", &t);
    while(t--){
        int n, m;
        scanf("%d %d\n", &n, &m);
        char c;
        for(int i = 1; i<=n; i++){
            for(int j = 1; j<=m; j++){
                scanf("%c", &c);
                int ans = c - 'a';
                // cout<<ans<<endl;
                a[j][ans]++;
            }
            cin.get();
        }
        for(int i = 1; i<=n-1; i++){
            for(int j = 1; j<=m; j++){
                scanf("%c", &c);
                int ans = c - 'a';
                // cout<<ans<<"*****"<<endl;
                a[j][ans]--;
            }
            cin.get();
        }
        for(int i = 1; i<=m; i++){
            for(int j = 0; j<26; j++){
                if(a[i][j] == 1){
                    // cout<<j<<"***"<<endl;
                    printf("%c", j+'a');
                    fflush(stdout);//交互题
                }
            }
        }
        puts("");
        for(int i = 1; i<=m; i++){
            for(int j = 0; j<26; j++)
                a[i][j] = 0;
        }
    }
    return 0;
}

——

C、 AquaMoon and Strange Sort

——
在这里插入图片描述
在这里插入图片描述
题意:给出长度为n的数组a[n],每一个ai都有一个属性(1或-1),初始属性全为1,
你可以执行一种操作:交换相邻的两个数然后将它们的属性反转(即1变为-1,-1变为1)。
现在需要用这个操作将该数组变成一个从小到大递增的有序数组,问经过一系列变换后,所有值的属性是否全为1;

解题思路:每一次翻转将属性值翻转,经过两次翻转属性值变为原值;要想变换后属性值都为1,即数组中每个元素因翻转偶数次或0次,题目暴力思路就是用冒泡的思想进行排序看每个元素交换多少次,看是否全为偶数次;但是冒泡的时间复杂度O(n^2)注定解决不了本题1e5的数据范围

但我们要看的是交换次数是否为偶数次,可以直接用快排对数组排序,对比排序前后的每个元素在两个数组中的位置,若同为奇数位或同为偶数位即方案可行;

题解
1、创建两个数组容器q和p,作为桶分别存储奇数位的数字和偶数位的数字;
2、排序前用桶加上奇数和偶数位上的数字;
3、排序后从将同为奇数或同为偶数的元素从桶里减去,若q桶里还有元素,则意味在变换中有一个奇位数变为了偶位数,若p桶中还有元素则意味有一个偶位数变为了奇位数,他们的变换次数都是奇数,输出NO;两桶都空则表示变换次数都是偶数,输出YES;

#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
#include <unordered_map>
 
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 100005;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
 
int a[N], q[N], p[N];
 
int main()
{
    //ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);
    int t;
    scanf("%d", &t);
    int n;
    while(t--){
        memset(q, 0, sizeof q);//每次循环桶清空
        memset(p, 0, sizeof p);
        scanf("%d", &n);
        for(int i = 1; i<=n; i++){
            scanf("%d", &a[i]);
            if(i&1)q[a[i]]++;
            else p[a[i]]++;
        }
        sort(a+1, a+n+1);
        for(int i = 1; i<=n; i++){
            if(i&1)q[a[i]]--;
            else p[a[i]]--;
        }
        int ans = 1;
        for(int i = 0; i<N; i++){
            if(q[i] || p[i]){
                ans = 0;
                break;
            }
        }
        if(ans)puts("YES");
        else puts("NO");
    }
    return 0;
}

——

D、AquaMoon and Chess

——
在这里插入图片描述
题意:给出一个长度为n的01数组表示一个棋盘,ai =1表示该位置上有棋子,ai = 0表示该位置上没有棋子;
当a[i] = 1的时候可以向左或向右隔一个棋子跳到a[i+2]或a[i-2]的位置上,a[i+1]或a[i-1]要为1;
问这个棋盘可以达多少种状态,数据对998244353 取模;

解题思路
1、首先可以看出,想要移动,至少要有两个连续的1,即最小的移动单位为11,且无论怎么移动,这两个1都不会分开,此时可以将两个连续的1看作一个整体,它可以到达棋盘上任意一个位置;

2、其次对于单独的1时,无论怎样移动,该位置上一定会有一个1,而对于连续的1长度len为奇数时,可以看作(len-1)/2个可移动的的单位和一个固定不动的1,且固定的1为连续奇数个1的中间那个;

3、设有m个可移动的1,有k个0,由此看来问题变为了将k个可移动的棋子插进m+1(因为每一个可移动的1占两个位置)个空位置中,答案是C(n+m-1,m-1) ;

题解:求C(n+m-1,m-1)的组合数就行了;

#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
#include <unordered_map>
 
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 100005;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
 
ll qmi(int a, int b, int p)
{
    ll res = 1 % p;
    while (b)
    {
        if (b & 1) res = res * a % p;
        a = a * (ll)a % p;
        b >>= 1;
    }
    return res;
}
 
int main()
{
    //ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);
    int t;
    scanf("%d", &t);
    int n;
    while(t--){
        scanf("%d", &n);
        string s;
        cin>>s;
        int len = s.length();
        int ans = 0;
        int cnt = 0;
        for(int i = 0; i<len; i++){
            if(s[i] == '1'){
                if(s[i+1] == '1'){
                    ans++;
                    i++;
                }
            }
            else if(s[i] == '0') cnt++;
        }
        ll res = 1;
        for(int i = cnt+ans; i>ans; i--){
            res*=i;
            res%=mod;
        }
        for(int i = cnt; i>=1; i--){
            res*=qmi(i, mod-2, mod);
            res%=mod;
        }
        cout<<res%mod<<endl;
    }
    return 0;
}

——
完结撒花!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值