Codeforces Round 925 (Div. 3) A-G题解

Codeforces Round 925 (Div. 3) A-G题解

A. Recovering a Small String Problem - A - Codeforces

题目概述:根据所给的 n n n输出相应的词性最小的3个小写拉丁字母。

其中 n n n的含义为三个字母的编号相加总和(a-z的编号分别对应着1-26)。

词性最小(lexicographically smallest)的含义是字典序最小。

题目类型:贪心,构造。

解题思路

根据题意贪心构造即可,下面提供两种思路。

AC代码:

贪心分支模拟

//
// Created by Mrlaolu on 2024/2/13.
//
#include <bits/stdc++.h>
 
#define int long long
#define endl '\n'

using namespace std;

void solve() {
  // code here
  int n;
  cin >> n;
  vector<char>ans(3);
  if(n >= 28)
  {
    ans[2] = 'z';
    n -= 26;
    if(n >= 27)
    {
      ans[1] = 'z';
      n -= 26;
      ans[0] = n-1 + 'a';
    }
    else
    {
      ans[1] = n - 2 + 'a';
      ans[0] = 'a';
    }
  }
  else
  {
    ans[2] = n - 3 + 'a';
    ans[1] = 'a';
    ans[0] = 'a';
  }
 
  for(int i = 0;i < 3;++i)
  {
    cout << ans[i];
  }
  cout << endl;
 
}
 
signed main() {
 
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}

还有一种通过三重for循环暴力找词性最小的办法,更为简洁

#include <bits/stdc++.h>
 
#define int long long
#define endl '\n'

using namespace std;

void solve() {
  // code here
  int n;
  cin >> n;
  for (int i = 1; i <= 26; i++) {
            for (int j = 1; j <= 26; j++) {
                for (int k = 1; k <= 26; k++) {
                    if (i + j + k == n) {
                        cout << char(i - 1 + 'a') << char(j - 1 + 'a') << char(k - 1 + 'a') << endl;
                        return;
                    }
                }
            }
        }
 
}
signed main() {
 
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}

B. Make Equal Problem - B - Codeforces

题目概述:给你 n n n 个正整数数字 a 1 − a n a_1-a_n a1an,它们的和保证能被 n n n 整除。你进行任意次(包括 0 0 0 次)把 a i a_i ai 的数值分点给 a j a_j aj 的操作,其中 i i i 必须小于 j j j(即 i < j i < j i<j )且每次操作 i i i j j j 都可变。问你能不能使该数组全变为平均数。

题目类型:贪心,模拟

解题思路

先算出这 n n n 个数字的平均数,记作 a v e ave ave。因为可以进行无数次题目种所提到的操作,只要 i < j i < j i<j,所以我们创造一个变量 s p a r e spare spare,从后往前遍历数组 a i a_i ai。只要 a i > a v e a_i > ave ai>ave,我们就把多余的数值放到 s p a r e spare spare 里,如果 a i < a v e a_i < ave ai<ave ,则把 s p a r e spare spare 里的值取出来给 a i a_i ai。如果某时刻 s p a r e < 0 spare < 0 spare<0,则说明排在后面的数字多余的值不足以填上前面的数,输出“NO”;反正如果到结束都 s p a r e ≥ 0 spare \ge 0 spare0,则输出“YES”;

AC代码

//
// Created by Mrlaolu on 2024/2/13.
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

void solve() {
  // code here
  int n;
  cin >> n;
  vector<int>arr(n);
  int sum = 0;
  for(int i = 0;i < n;++i)
  {
    cin >> arr[i];
    sum += arr[i];
  }
  int ave = sum / n;

  int spare = 0;
  for(int i = 0;i < n;++i)          
  {
    if(spare < ave - arr[i])
    {cout << "NO\n";return;}
    else
    {
      spare -= ave - arr[i];       //直接利用负负得正原理,少掉对ave-arr[i]正负的判断
    }
  }

  cout << "YES\n";
}

signed main() {

  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}

C. Make Equal Again Problem - C - Codeforces

题目类型:贪心

解题思路

  1. 因为只有一次操作机会,所以我们要变也是要把位于中间的数全变成相同的数值。
  2. 根据贪心的思想,我们要获得最小布尔值(burles),就要 j − i j-i ji 尽可能小,也就是尽可能少的两端的数包含进去。所以我们就去找从两端( a 0 a_0 a0 a n − 1 a_{n-1} an1 )是不是相等。如果相等,从这两个的开始的连续相同子串为多长,答案就为 n − (从 a 0 开始的连续相同子串 + 从 a n − 1 开始的连续相同子串) n-(从a_0开始的连续相同子串+从a_{n-1}开始的连续相同子串) n(从a0开始的连续相同子串+an1开始的连续相同子串)。如果不相等,则为 n − M A X (从 a 0 开始的连续相同子串 , 从 a n − 1 开始的连续相同子串) n-MAX(从a_0开始的连续相同子串,从a_{n-1}开始的连续相同子串) nMAX(从a0开始的连续相同子串,an1开始的连续相同子串)

AC代码

//
// Created by Mrlaolu on 2024/2/13.
//

#include <bits/stdc++.h>

#define int long long
#define endl '\n'
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))

using namespace std;

void solve() {
  // code here
  int n;
  cin >> n;
  vector<int>arr(n);
  int sum = 0;
  for(int i = 0;i < n;++i)
  {
    cin >> arr[i];
  }

  int fsum = 1;
  for(int i = 1;i < n;++i)
  {
    if(arr[i] == arr[0])
    {fsum += 1;}
    else
    {break;}
  }

  int bsum = 1;
  for(int i = n - 2;i >= 0;--i)
  {
    if(arr[i] == arr[n - 1])
    {bsum += 1;}
    else
    {break;}
  }
  if(arr[n - 1] == arr[0])              
  {cout << MAX(n-bsum-fsum,0) << endl;}    //因为bsum+fsum >= n可以说明整个数组的数都相同 所以直接这样写输出0   
  else
  {cout << n-MAX(bsum,fsum) << endl;}
}
signed main() {

  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}

D. Divisible Pairs [Problem - D - Codeforces]

题目类型:预处理,模的性质

解题思路

  1. 根据模的性质 ( a ± b )   m o d   p = ( a   m o d   p ± b   m o d   p )   m o d   p (a \pm b) \bmod p = (a \bmod p \pm b \bmod p) \bmod p (a±b)modp=(amodp±bmodp)modp 可以发现,只要两个数的余数相加能被 x x x 整除,相减能被 y y y 整除,就可满足题意。
  2. 我们可以先把每个数字预处理,分别对 x x x y y y 进行取模并存储到 map 里,匹配时直接在 map 里找{ ( x − a i   m o d   x )   m o d   x , a i   m o d   y (x - a_i \bmod x) \bmod x,a_i \bmod y (xaimodx)modx,aimody}所对应的相应的个数即可。(需要前置知识 pair 和 map )
  3. 需要特别注意的时,可能存在 ( x − a i   m o d   x )   m o d   x = a i   m o d   x (x - a_i \bmod x) \bmod x = a_i \bmod x (xaimodx)modx=aimodx,而匹配时不能与自身匹配,所以要特判这种情况,如果出现则对答案 − 1 -1 1 ,因为 i < j i < j i<j ,所以要对最终答案 ÷ \div ÷ 2 2 2

AC代码

//
// Created by Mrlaolu on 2024/2/13.
//

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
using namespace std;

void solve() {
  // code here
  int n,x,y;
  cin >> n >> x >> y;
  vector<int>arr(n);
  map<pair<int,int>,vector<int>>cate;      //用于分类存储每个数与x和y取余后的数

  for(int i = 0;i < n;++i)
  {
    cin >> arr[i];
    cate[{arr[i] % x,arr[i] % y}].push_back(arr[i]);
  }

  int ans = 0;
  for(int i = 0;i < n;++i)
  {
    if(cate.count({(x - arr[i] % x) % x,arr[i] % y}))ans += cate[{(x - arr[i] % x) % x,arr[i] % y}].size();
    if((x - arr[i] % x) % x == arr[i] % x)   //(3)所提到的特殊情况
    {ans -= 1;} 
  }

  cout << ans / 2 << endl;

}
signed main() {

  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}


E. Anna and the Valentine’s Day Gift Problem - E - Codeforces

题目类型:博弈

解题思路

  1. Anna 要使最终最后一个数的位数最小,Sasha 要使最终最后一个数的位数最大
  2. 对 Anna 最有利的操作是把后缀零最多的数给倒置(如 158000 158000 158000 1580 1580 1580 都能倒置成 851 851 851 ,所以我们优先选 158000 158000 158000 可以使最后的位数少 3 3 3 位)。
  3. 对 Sasha 最有利的操作是把后缀零最多的数后面连接一个数,Anna 就不能通过倒置使这些后缀零(如 158000 158000 158000 1580 1580 1580 851 851 851 ,我们选择把 158000 158000 158000 851 851 851 连接成 158000851 158000851 158000851 为 Sasha 的最有利操作)。
  4. 综上所述,我们可以把每个数的位数和的总和先加起来,并把后缀零个数求出来存到数组里。把数组按降序排序,再根据题目所讲的Anna先手Sasha后手隔一个减去后缀零的个数,即 b i t = b i t − ∑ k = 1 n / 2 a 2 k − 1 bit = bit - \sum_{k=1}^{n / 2}a_{2k-1} bit=bitk=1n/2a2k1

AC代码

//
// Created by Mrlaolu on 2024/2/13.
//

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

void solve() {
  // code here
  int n,m;
  cin >> n >> m;
  vector<int>arr(n);

  int bit = 0;                         //存储位数和的总和
  vector<int>zero(n);                  //存储后缀零个数的数组

  for(int i = 0;i < n;++i)
  {
    cin >> arr[i];
    string temp = to_string(arr[i]);     //通过to_string快速求位数
    bit += temp.size();
    for(int j = temp.size() - 1;j >= 0;--j)    //求后缀0
    {
      if(temp[j] == '0')
      {zero[i]++;}
      else
      {break;}
    }
  }

  sort(zero.begin(),zero.end(),greater<int>());   
  for(int i = 0;i < n;i+=2)             //隔一个减后缀0的个数
  {
    bit -= zero[i];
  }
  if(bit > m){cout << "Sasha\n";}
  else
  {cout << "Anna\n";}
}

signed main() {

  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}


F. Chat Screenshots Problem - F - Codeforces

题目类型:图论

前置知识:拓扑排序

解题思路

  1. 这道题最主要的就是判断给你的这几个序列有没有矛盾的地方,我们可以把每一条顺序看作是一个有向图,由前往后一直指下去。比如顺序 1 2 3 4 5 就相当于 2→3 3→4 4→5 。我们把这个几个序列中产生的有向边放到一个有向图里。如果产生了环,则说明有矛盾产生,不能生成截图;否则就没有。而我们可以通过拓扑排序的性质判断有没有环(即如果产生了环,必有元素最终的入读不为 0 0 0 ,没有进入队列)
  2. 还有个思路是jls在群里提出的,即如果两个顺序的提供者位置不是相邻的(如果是相邻的则要三个),则这个截图就可以确定下来了(或者产生不了截图),后来的顺序只要和这个顺序一样就能产生。(这里只是提供一个思路,未提供ac代码)

AC代码

//
// Created by Mrlaolu on 2024/2/13.
//

#include <bits/stdc++.h>

#define int long long
#define endl '\n'
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
using namespace std;

void solve() {
  // code here
  int n,k;
  cin >> n >> k;
  vector<vector<int>>arr(k,vector<int>(n));
  vector<vector<int>>a(n + 1);                           //用于存ta指向的节点
  vector<int>in(n + 1);                                  //用于存各个节点的入度
  vector<int>ans;

  for(int i = 0;i < k;++i)
  {
    for(int j = 0;j < n;++j)
    {
      cin >> arr[i][j];
    }
  }

  for(int i = 0;i < k;++i)
  {
    for(int j = 1;j < n - 1;++j)
    {
      a[arr[i][j]].push_back(arr[i][j + 1]);
      in[arr[i][j + 1]]++;
    }
  }

  queue<int>que;                                     //用队列和栈都一样
  for(int i = 1;i <= n;++i)
  {
    if(!in[i]){que.push(i);ans.push_back(i);}        //预处理 将入读为0的都放进队列
  }
  while(que.size())
  {
    int temp = que.front();
    que.pop();
    for(int i = 0;i < a[temp].size();++i)
    {
      in[a[temp][i]]--;
      if(!in[a[temp][i]]){que.push(a[temp][i]);ans.push_back(a[temp][i]);}
    }
  }

  for(int i = 1;i <= n;++i)
  {
    if(in[i] != 0){cout << "NO\n";return;}
  }

    cout << "YES\n";

}
signed main() {

  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}


G. One-Dimensional Puzzle Problem - G - Codeforces

题目类型:组合排列

前置知识:乘法逆元,组合数求法,隔板法

解题思路

  1. 我们可以发现 1 1 1 2 2 2 是不能自我连接的,而 3 3 3 4 4 4 是可以的。这就表明一个 1 1 1 2 2 2 是相伴相生的,而 3 3 3 4 4 4 可以看作是插在 1 1 1 2 2 2 中间 或者 1 1 1 2 2 2 两侧的可有可无的东西。

  2. 根据上面这条分析和样例,我们可以发现 1 1 1 2 2 2 的数量差不能大于 1 1 1 ,不然就有匹配失败而被孤立的 1 1 1 2 2 2 ,使其不能拼成一条链。而 3 3 3 4 4 4 只用看作插在 1 1 1 2 2 2 中间或两侧就可以了。根据 1 1 1 2 2 2 之间可以没有插 3 3 3 4 4 4 (分组可空)的性质,我们可以想到用隔板法做这道题(不会隔板法的可以去搜视频学一下)。

  3. 如果 1 1 1 的数量比 2 2 2 多,则以 1 1 1 为隔板插,否则以 2 2 2 为隔板插。因为数量多就说明侧边的那两个拼图是它,所以我们以它为隔板插。

  4. 1 1 1 2 2 2 的数量相同时,我们注意到这条链的主链有两条拼接方法,一个为 1 1 1 在最左侧,一个为 1 1 1 在最右侧,我们便要把这两个情况加起来。(没有理解到的可以自己画图试一试,就能有所体会了)

  5. 因为涉及到组合数取模的问题,所以我们要用到乘法逆元。(不会的话也要去搜视频学一下)

AC代码

//
// Created by Mrlaolu on 2024/2/14.
//

#include <bits/stdc++.h>

#define int long long
#define endl '\n'
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
using namespace std;

const int mod = 998244353;
const int N = 2000005;

int fac[N], jv[N], inv[N];
void com_init(int n) {
  jv[0] = fac[0] = 1;
  for (int i = 1; i <= n; i++) {
    inv[i] = i == 1 ? 1 : (mod - mod / i) * inv[mod % i] % mod;
    fac[i] = fac[i - 1] * i % mod;
    jv[i] = jv[i - 1] * inv[i] % mod;
  }
}
int com(int n, int m) {
  if (n < m || m < 0) return 0;
  return fac[n] * jv[n - m] % mod * jv[m] % mod;
}

void solve() {
  // code here
  int a,b,c,d;
  cin >> a >> b >> c >> d;
  if(a == 0 && b == 0 && c == 0 && d == 0)
  {
    cout << 1 << endl;
    return;
  }

  if(abs(a - b) > 1)
  {
    cout << 0 << endl;return;
  }
  else if(a == b && a == 0)
  {
    cout << (c == 0 || d == 0) << endl;
  }
  else
  {
    if(a > b)
    {
      cout << com(c + a - 1,a - 1) * com(d + a - 1,a - 1) % mod << endl;
    }
    else if(a < b)
    {
      cout << com(c + b - 1,b - 1) * com(d + b - 1,b - 1) % mod << endl;
    }
    else
    {
      cout << (com(c + b,b) * com(d + b - 1,b - 1) % mod + com(c + b - 1,b - 1) * com(d + b,b) % mod) % mod << endl;
    }
  }

}

signed main()
{

  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  cin >> t;
  com_init(2e6);
  while (t--) {
    solve();
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值