您的位置:首页 > 其它

Educational Codeforces Round 32[题解]

2017-11-10 09:45 399 查看
比赛时只过了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))
{

4000
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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: