快手算法笔试题,两个动态规划,一个签到题。数据太恶心了,魔法深渊那题,没给模,后来是我自己根据结果猜出来的,模是 1000000003 1000000003 1000000003,居然还不是常规的 1000000007 1000000007 1000000007;善变的同伴那题,应该是卡常数了,而且代码一会过一会不过。。。
题目链接:点这儿。
魔法深渊
题目
前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。
由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。
已知深渊有N
层台阶构成(1 <= N <= 1000)
,并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、…),请你编程告诉月神,月神有多少种方法爬出深渊
输入:
输入共有M
行,(1 <= M <= 1000)
第一行输入一个数M
表示有多少组测试数据,
接着有M
行,每一行都输入一个N
表示深渊的台阶数
输出:
输出可能的爬出深渊的方式
样例:
4 1 2 3 4
1 2 3 6
解析
简单动态规划,和上楼梯的斐波拉契数列有点类似,照着那个想一想就明白了。
注意,一定要取模,不然数据范围会炸,虽然题目中没有给出模,但是它的输出数据是取了模的,开头也说了,我试出来的模是 1000000003 1000000003 1000000003。
#include <bits/stdc++.h>
int main()
{
int p2[10] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
std::vector<long long> dp(1001, 0);
dp[0] = 1;
for (int i = 1; i <= 1000; ++i) {
for (int j = 0; j < 10 && i >= p2[j]; ++j) {
dp[i] += dp[i - p2[j]];
dp[i] %= 1000000003LL;
}
}
int T;
std::cin >> T;
for (int n; T--; std::cout << dp[std::cin >> n, n] << std::endl) {}
return 0;
}
善变的同伴
题目
又到了吃午饭的时间,你和你的同伴刚刚研发出了最新的GSS-483型自动打饭机器人,现在你们正在对机器人进行功能测试。
为了简化问题,我们假设午饭一共有N
个菜,对于第i
个菜,你和你的同伴对其定义了一个好吃程度(或难吃程度,如果是负数的话……)A[i]
。
由于一些技(经)术(费)限制,机器人一次只能接受一个指令:两个数L, R
——表示机器人将会去打第L~R
一共R-L+1
个菜。
本着不浪费的原则,你们决定机器人打上来的菜,含着泪也要都吃完,于是你们希望机器人打的菜的好吃程度之和最大
然而,你善变的同伴希望对机器人进行多次测试(实际上可能是为了多吃到好吃的菜),他想知道机器人打M
次菜能达到的最大的好吃程度之和
当然,打过一次的菜是不能再打的,而且你也可以对机器人输入-1, -1
,表示一个菜也不打
输入:
第一行:N, M
第二行:A[1], A[2], ..., A[N]
输出:
一个数字S
,表示M
次打菜的最大好吃程度之和
样例:
7 2 1 2 3 -2 3 -10 3 7 4 1 2 3 -2 3 -10 3
10 12
解析
分析剥离一下,这个题就是最大m段子段和的装饰版。这个也可以自己上网找找资料,理解一下这个动态规划,很基础。
注意:二维动态规划,复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度要做到 O ( n ) O(n) O(n),因此用滚动数组优化一下,但是这个题卡常数,交上去的代码时过时不过的。
#include <bits/stdc++.h>
#define MAX_SIZE 1000000
using LL = long long;
const LL inf = 0x3f3f3f3f;
LL a[MAX_SIZE];
LL dp[2][MAX_SIZE];
int main()
{
for (LL n, m, pre; EOF != std::scanf("%lld%lld", &n, &m); ) {
//std::vector<LL> a(n);
//std::vector< std::vector<LL> > dp(2, std::vector<LL>(n + 1, 0));
for (int i = 1; i <= n; std::scanf("%lld", &a[i++])) {}
for (int i = 1; i <= m; ++i) {
pre = dp[i & 1][i - 1] = -inf;
for (int j = i; j <= n - m + i; ++j) {
pre = std::max(pre, dp[(i - 1) & 1][j - 1]);
dp[i & 1][j] = std::max(dp[i & 1][j - 1], pre) + a[j];
}
}
LL ans = -inf;
for (int i = std::min(m, n); i <= n; ans = std::max(ans, dp[std::min(n, m) % 2][i++])) {}
std::printf("%lld\n", ans);
}
return 0;
}
字符串归一化
题目
通过键盘输入一串小写字母(a~z)
组成的字符串。
请编写一个字符串归一化程序,统计字符串中相同字符出现的次数,并按字典序输出字符及其出现次数。
例如字符串"babcc
“归一化后为”a1b2c2
"
输入:
每个测试用例每行为一个字符串,以’\n
'结尾,例如cccddecca
输出:
输出压缩后的字符串ac5d2e
样例:
dabcab
a2b2c1d1
解析
这个,随便怎么做都可以。
#include <bits/stdc++.h>
int main()
{
for (std::string str; std::cin >> str; std::cout << std::endl) {
std::map<char, int> mp;
std:for_each(std::begin(str), std::end(str), [&] (const char c) {
mp[c]++;
});
std::for_each(std::begin(mp), std::end(mp), [] (const std::pair<char, int> & ele) {
std::cout << ele.first << ele.second;
});
}
return 0;
}