当前位置:   article > 正文

蓝桥杯 双周赛 第16场 小白赛 题目复盘 (2024年8月10日)

蓝桥杯 双周赛 第16场 小白赛 题目复盘 (2024年8月10日)

在这里插入图片描述

3. 织女的考验

  • 下面的代码看似很正确,但忽略了一个细节,下面判断是否有字母数量不同时,用abs(cnt[i]) == 1判断,这里忽略了abs(cnt[i]) 等于其他值的情况(YES和NO都存在)
#include <iostream>
#include <cstring>
using namespace std;

int n;
int cnt[30];
bool check(string s, string t) {
  memset(cnt, 0, sizeof cnt);
    if (s.size() == 1) {
      return true;
    }
    for(int i = 0; i < s.size(); i++) {
      cnt[s[i] - 'a']++;
      cnt[t[i] - 'a']--;
    }
    int num = 0;
    for (int i = 0; i < 26; i++) {
      if (abs(cnt[i]) == 1) num++;
      if (num > 2) return false;
    }
  return true;
}
int main() {
  cin >> n;
  string s, t;
  while(n--) {
    cin >> s >> t;
    if (check(s, t)) cout << "YES" << endl;
    else cout << "NO" << endl;
  }
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 修改后的代码
  • 猜想1: 用num += cnt[i]; 最后判断num是否等于0,来判断答案。
  • 不能,因为所有长度相等的字符串都满足这条件。
  • 猜想2:用num += abs(cnt[i]);最后用num是否大于0判断。
  • 不能,满足题目的只有两种情况,(1)两个字符串字母数量都相同,(2) 有两个字母数量不同,且都相差1,一个相减结果-1一个1。
#include <iostream>
#include <cstring>
using namespace std;

int n;
int cnt[30];
bool check(string s, string t) {
  memset(cnt, 0, sizeof cnt);
    if (s.size() == 1) {
      return true;
    }
    for(int i = 0; i < s.size(); i++) {
      cnt[s[i] - 'a']++;
      cnt[t[i] - 'a']--;
    }
    int num = 0;
    for (int i = 0; i < 26; i++) {
      num += abs(cnt[i]);
      if (num > 2) return false;
    }
  return true;
}
int main() {
  cin >> n;
  string s, t;
  while(n--) {
    cin >> s >> t;
    if (check(s, t)) cout << "YES" << endl;
    else cout << "NO" << endl;
  }
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

4. 仙男仙女

  • 我第一次想到的是用前缀和来做,但是,没有考虑好内存问题(需要开int * 1e9)。还有,应该将pos的值维护完以后,求好前缀和以后,在计算ans。
#include <iostream>
using namespace std;
const int N = 1e5 + 01, M = 1e9 + 10;
int a[N], n, p[N], b[N];
int pos[M];

int main()
{
  int ans = 0;
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> p[i];
  }
  for (int i = 1; i <= n; i++) {
    cin >> b[i];
  }
  for (int i= 1; i <= n; i++) {
    pos[p[i]]++;
    pos[i] += pos[i - 1];
    int l = max(0, i - b[i] - 1), r = min(n, i + b[i] + 1 );
    if ((pos[i - 1] - pos[l] == 0) && (pos[r] - pos[i] == 0)) {
      ans++;
    }
  }
  cout << ans;
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 换一种思路,可以直接用pair储存位置和距离,按位置排序,最后求ans。
#include<iostream>
#include<algorithm>

using namespace std;
#define x first
#define y second
const int N = 1e5 + 10;
int n;
pair<int, int> pa[N];

int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> pa[i].x;
  }
  for (int i = 1; i <= n; i++) cin >> pa[i].y;
  sort(pa + 1, pa + n + 1);
  int ans = 0;
  if (n > 1 && pa[1].x + pa[1].y < pa[2].x) ans++;
  if (n > 1 && pa[n].x - pa[n].y > pa[n-1].x) ans++;
  for (int i = 2; i < n; i++) {
    if (pa[i].x + pa[i].y < pa[i + 1].x && pa[i].x - pa[i].y > pa[i - 1].x) ans++;
  }
  cout << ans;
  return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

5. 牛郎的微信群

  • 分析: n 最大 10^5所以最大复杂度只能是 O ( n l o g ( n ) ) O( n log(n) ) O(nlog(n))
  • 我想,构建一个树. f[i] = g[p1] + g[p2] …(其中,p1 p2 … 是与i直接相连的节点,f[i]表示与i距离为2的节点,g[p]表示与节点p距离为1的点)。ans = (f[1] + f[2] + … + f[n]) / 2;
  • 需要注意的点,(1)e和ne的大小 (2) f[r] += g[t] - 1; 减一表示要减去他自己。
#include<iostream>
using namespace std;

const int N = 2e5 + 10;
int n, ind = 0, h[N], e[N * 2], ne[N * 2], g[N], f[N];

void add(int a, int b) {
  e[++ind] = b;
  ne[ind] = h[a];
  h[a] = ind;
}
int ans = 0;
bool bs[N];

void dfs(int r) {
  bs[r] = true;
 // cout << r << " ";
  for (int i = h[r]; i; i = ne[i]) {
    int t = e[i];
    f[r] += g[t] - 1;
    if (bs[t]) continue;
    dfs(t);
  }
}

int main() {
  cin >> n;
  int x, y;
  for (int i = 0; i < n - 1; i++) {
    cin >> x >> y;
    add(x, y);
    add(y, x);
    g[x]++;
    g[y]++;
  }
  dfs(1);
  for (int i = 1; i <= n; i++) {
    cout << f[i] << " ";
  }

  return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

6. 就别重逢

题意可抽象为:给你n和k,求用不小于k的任意个正整数组成和不大于n的排列(有顺序)有多少种?
分析:
看到这个问题的时候,第一个就想到的是用动态规划来做,公式推导如下。(其中, f [ i ] f[i] f[i]表示刚好达到亲密度 i i i有多少种方法)

f[i] = f[0 1 2 .. i - k]
f[i + 1] = f[0 1 2 3 .. i-k i+1-k] = f[i] + f[i+1-k];
f[i] = f[i-1] + f[i-k];
  • 1
  • 2
  • 3

通过程序如下:(题目要求达到n有多少种变化,也就是将f[k] f[k+1] … f[n] 加起来)

#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, k;
LL f[N], p = 1e9 + 7;

int main()
{
  cin >> n >> k;
  f[k] = 1;
  LL ans = 2;
  for (int i = k + 1; i <= n; i++) {
    f[i] = (f[i-1] + f[i-k]) % p;
    ans = (ans + f[i]) % p;
  }
  cout << ans;
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/985732
推荐阅读
相关标签
  

闽ICP备14008679号