Educational Codeforces Round 32[题解]

比赛时只过了5道题,ABCDE。先写下题解,剩下的FG等补完题再更。

A:

题意:

给定一个数列, 求极值点的个数。极值点定义为比相邻的两个数都大,或者都小的点。

题解

直接一遍扫过去判断即可。注意端点只有一个相邻的数,遍历范围为2 到 n - 1。判断条件为a[i] > a[i - 1] && a[i] > a[i + 1] || a[i] < a[i - 1] && a[i] < a[ i + 1]。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int a[maxn];
int main()
{
  int n;
  while(~scanf("%d", &n))
  {
    for(int i = 1; i <= n; i++)
      scanf("%d", &a[i]);
    int ans = 0;
    if(n <= 2)  ans = 0;
    else
    {
      for(int i = 2; i <= n - 1; i++)
        if(a[i] > a[i - 1] && a[i] > a[i + 1] || a[i] < a[i - 1] && a[i] < a[ i + 1])
          ans++;
    }
    printf("%d\n", ans);
  }
}

B:

题意:

给定一个机器人的每一步的运动方向,问你机器人最多按这个走多少步能保证回到起点。

题解:

分析易知,若向上(U)走一步,则之后必须需要向下(D)走一步才能回到原点,左右同理。
因此最多上下的次数为U的次数和D的次数中的最小值*2。
于是答案就是U的次数和D的次数中最小值加上L和R中的最小值。再乘以2就是。

#include <bits/stdc++.h>
using namespace std;
int get(char c)
{
  if(c == 'U')  return 1;
  else  if(c == 'D')  return 2;
  else  if(c == 'L')  return 3;
  else  return 4;
}
char buf[1010];
int cnt[5];
int main()
{
  int n;
  while(~scanf("%d", &n))
  {
    scanf(" %s", buf);
    memset(cnt, 0, sizeof cnt);
    for(int i = 0; buf[i]; i++)
    cnt[get(buf[i])]++;
    int ans = 0;
    ans = 2 * min(cnt[1], cnt[2]) + 2 * min(cnt[3], cnt[4]);
    printf("%d\n", ans);
  }
}

C:

题意:

给定一个字符串,求最大的k,使得存在一个字符c是该串的k-dominant character. k-dominant character定义为字符串的任意长度为k的子串中均包含有字符c。

题解:

对于一个给定的字符c,考虑其可以构成的k值的最小值。任意长度为k的子串都包含有c,也就是串中c的间隔以及c与端点的最大距离为k。因此最小值即为所有c间隔中的最大值。再对于所有字符的最小k值取个最小值,即为答案。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int pos[28];
int Mx[28];
char buf[maxn];
int main()
{
  while(~scanf(" %s", buf))
  {
    memset(pos, -1, sizeof pos);
    memset(Mx, 0, sizeof Mx);
    int len = strlen(buf);
    for(int i = 0; buf[i]; i++){
      int t = buf[i] - 'a' + 1;
      Mx[t] = max(Mx[t], i - pos[t]);
      pos[t] = i;
    }
    for(int i = 1; i <= 26; i++)
    {
      Mx[i] = max(Mx[i], len - pos[i]);
      pos[i] = len;
    }
    int ans = maxn;
    for(int i = 1; i <= 26; i++)
      if(Mx[i])
        ans = min(ans, Mx[i]);
    printf("%d\n", ans);
  }
}

D:

题意:

给定n,k,问对于一个n的全排列,最多错排k个元素的排列数。

题解:

由错排公式有D0 = 1,D1 = 0, D2 = 1, D3 = 2, D4 = 9;
因此恰好错排k个的数目为C(n,k) * Dk;
所求排列数为 ki=1C(n,i)Di
数据范围比较小,直接算即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll C(ll n, ll k)
{
  ll res = 1;
  for(ll i = 1, j = n; i <= k; i++, j--)
    res = res * j / i;
  return res;
}
int main()
{
  ll n, k;
  while(~scanf("%lld%lld", &n, &k))
  {
    ll ans = 0;
    switch(k)
    {
      case 4: ans += C(n, 4) * 9;
      case 3: ans += C(n, 3) * 2;
      case 2: ans += C(n, 2);
      case 1: ans++;
    }
    printf("%lld\n", ans);
  }
}

E:

题意:

给出n和m,一个n个数a[i],求从中任意选出一些数,使得 a[i]%m 的最大值。

题解:

先对a[i] 取模,然后问题就类似于一个超大容量背包问题,直接dp显然不可行。我们可以采取常用的对半枚举,然后二分查找的方法求解。
枚举对前n / 2个元素能够构成的所有情况,加入到set ssr1中,再枚举剩余的元素,加入到set ssr2中,然后枚举一个集合的元素x,查找另一个集合中 <= m - 1 - x 的最大元素。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
set<ll> ssr1, ssr2, sr;
set<ll>::iterator ite, ite2;
ll a[110];
int main()
{
  int n;
  ll m;
  while(~scanf("%d%lld", &n, &m))
  {
    if(n == 1)
    {
      ll t;
      scanf("%lld", &t);
      printf("%lld\n", t % m);
    }
    else
    {
      for(int i = 1; i <= n; i++)
      {
        scanf("%lld", &a[i]);
        a[i] %= m;
      }
      ssr1.clear();
      ssr1.insert(0);
      for(int i = 1; i <= n / 2; i++)
      {
        sr.clear();
        for(ite = ssr1.begin(); ite != ssr1.end(); ite++)
          sr.insert((*ite + a[i]) % m);
        for(ite = sr.begin(); ite != sr.end(); ite++)
          ssr1.insert(*ite % m);
      }
      ssr2.clear();
      ssr2.insert(0);
      for(int i = n / 2 + 1; i <= n; i++)
      {
        sr.clear();
        for(ite = ssr2.begin(); ite != ssr2.end(); ite++)
          sr.insert((*ite + a[i]) % m);
        for(ite = sr.begin(); ite != sr.end(); ite++)
          ssr2.insert(*ite % m);
      }
      ll ans = 0;
      for(ite = ssr1.begin(); ite != ssr1.end(); ite++)
      {
        ll t = *ite;
        ite2 = ssr2.lower_bound(m - t);
        while(ite2 == ssr2.end() || *ite2 > m - 1 - *ite) ite2--;
          ans = max(ans, (*ite + *ite2) % m);
      }
      printf("%lld\n", ans);
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值