Codeforces Round #382 (Div. 2)
A. Ostap and Grasshopper
题意:
给出一个字符串(n<=100),问从‘G’字符的位置可否每次只可恰好跳步长为k的一步(只可跳到非‘#’字符的位置且不可跳出字符串外),跳若干步到达‘T’字符的位置。
分析:
朴素模拟,分别从左右跳,时间复杂度为O(n)。
代码如下:
#include <cstdio>
#include <cstring>
const int maxn = 100 + 3;
int n, k;
char arr[maxn];
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%d", &n)) {
scanf("%d", &k);
memset(arr, 0, sizeof(arr));
scanf("%s", arr);
int g_loc;
for (int i = 0; i < strlen(arr); i++)
if (arr[i] == 'G') {
g_loc = i; break;
}
bool ok = false;
for (int i = 1; g_loc + i * k < strlen(arr); i++) {
if (arr[g_loc + i * k] == 'T') {
ok = true; break;
}
else if (arr[g_loc + i * k] == '#') break;
}
if (!ok)
for (int i = 1; g_loc - i * k >= 0; i++) {
if (arr[g_loc - i * k] == 'T') {
ok = true; break;
}
else if (arr[g_loc - i * k] == '#') break;
}
ok ? puts("YES") : puts("NO");
}
return 0;
}
B. Urbanization
题意:
已知n个居民的财富值(<=100000),将这n(n<=100000)个居民抽取部分(或全部)分别到容量为n1和n2的两个城市(n1+n2<=n),使得这两个城市人们的人均财富值之和尽量大,求这个最大的人均财富值之和。
分析:
排序+贪心。先将n个居民的财富值排序,假设n1<n2,选最多财富的n1个人去容量为n1的城市,次n2个人去容量为n2的城市,时间复杂度为O(nlogn)。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 100000 + 3;
int n, n_1, n_2;
double wealth[maxn];
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%d", &n)) {
scanf("%d%d", &n_1, &n_2);
for (int i = 1; i <= n; i++) scanf("%lf", &wealth[i]);
sort(wealth + 1, wealth + 1+ n);
if (n_1 > n_2) swap(n_1, n_2);
double large_one = 0.0;
for (int i = 0; i < n_1; i++)
large_one += wealth[n - i];
large_one /= double(n_1);
double less_one = 0.0;
for (int i = 0; i < n_2; i++)
less_one += wealth[n - n_1 - i];
less_one /= double(n_2);
printf("%.8lf\n", large_one + less_one);
}
return 0;
}
C. Tennis Championship
题意:
现将举办一个锦标赛,有n个选手(2<=n<=1e18),每场比赛都是两个选手之间进行,输的一方将被立即淘汰,但进行比赛的这两名选手,他们各自已经参加过的比赛的场数相差不可超过1,求锦标赛的冠军参加过的比赛场数最多可能为多少。
分析:
数学、递推。设ai表示冠军一共比赛i场所需要最少的选手人数,可知:a0=1,a1=2,a2=3,a3=5,...,仔细分析可得到如下递推关系:ai=ai-1 + ai-2 (i>=2),因此答案即为求最大的i使得ai<=n,数列{an}为类似Fibonacci数列的数列,因而增长幅度非常大,再由n的范围,因此可知时间复杂度为O(100)。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
ll n;
int cal() {
ll pre_pre = 1LL, pre = 2LL;
int ans = 1;
while (pre <= n) {
ll buf = pre_pre + pre;
pre_pre = pre; pre = buf;
ans += 1;
}
return ans - 1;
}
int main() {
//freopen("input.txt", "r", stdin);
while (~scanf("%I64d", &n)) printf("%d\n", cal());
return 0;
}
D. Taxes
题意:
一个人他赚的钱为n(2<=n<=2*10^9),若按照税法,则需要交的税为不等于n的n的最大因数,如今这个人想偷税,他将n拆分为若干个ni的和,即n=n1+n2+...+nk(k为任意值,可等于1),但是其中ni不能等于1,拆分完后,他总共交的税即为每份ni按照税法交的税之和。求他交的税的最小值。
分析:
数论。核心想法就是将n拆分为尽量少的数之和,且这些数最好为质数。哥德巴赫猜想:任一大于2的偶数都可写成2个质数之和,还有一种等价说法:任一大于5的奇数都可写成3个质数之和。还有:奇数+-奇数=偶数,奇数+-偶数=奇数。注意到2既为质数也为偶数。所以当n=2、3、4、5时特判即可,当n>5时,n为偶数,最优就是按照第一种哥德巴赫猜想,若n为奇数,若n为质数则显然可知答案,若n不为质数,则尝试分解为n=2+一个质数,即判断n-2是否为质数,是则好说,若不是则按照哥德巴赫猜想第二种形式可知答案。时间复杂度为O(sqrt(n))。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
bool is_prime(int num) {
int bound = floor(sqrt(num) + 0.5);
for (int i = 2; i <= bound; i++)
if (num % i == 0) return false;
return true;
}
int for_odd(int num) {
if (is_prime(num)) return 1;
else return is_prime(num - 2) ? 2 : 3;
}
int main() {
//freopen("input.txt", "r", stdin);
int n;
while (~scanf("%d", &n)) {
if (n == 2 || n == 3 || n == 5) puts("1");
else (n & 1) ? printf("%d\n", for_odd(n)) : puts("2");
}
return 0;
}