美团点评软件测试编程题,CodeM美团点评编程竞赛 资格赛题解(下)!

原标题:CodeM美团点评编程竞赛 资格赛题解(下)!

关注我哟

本文为美团codeM竞赛资格赛后三题题解。

送外卖

题目描述

n 个小区排成一列,编号为从 0 到 n-1 。一开始,美团外卖员在第0号小区,目标为位于第 n-1 个小区的配送站。

给定两个整数数列 a[0]~a[n-1] 和 b[0]~b[n-1] ,在每个小区 i 里你有两种选择:

1) 选择a:向前 a[i] 个小区。

2) 选择b:向前 b[i] 个小区。

把每步的选择写成一个关于字符 ‘a’ 和 ‘b’ 的字符串。求到达小区n-1的方案中,字典序最小的字符串。如果做出某个选择时,你跳出了这n个小区的范围,则这个选择不合法。

• 当没有合法的选择序列时,输出 “No solution!”。

• 当字典序最小的字符串无限长时,输出 “Infinity!”。

• 否则,输出这个选择字符串。

字典序定义如下:串s和串t,如果串 s 字典序比串 t 小,则

• 存在整数 i ≥ -1,使得∀j,0 ≤ j ≤ i,满足s[j] = t[j] 且 s[i+1] < t[i+1]。

• 其中,空字符 < ‘a’ < ‘b’。

输入描述:输入有 3 行。第一行输入一个整数 n (1 ≤ n ≤ 10^5)。第二行输入 n 个整数,分别表示 a[i] 。第三行输入 n 个整数,分别表示 b[i] 。−n ≤ a[i], b[i] ≤ n输出描述:输出一行字符串表示答案。输入例子:75 -3 6 5 -5 -1 6-6 1 4 -2 0 -2 0输出例子:abbbb

题解:

终于通过所有数据了。

#include

#include

#include

#include

#include

using namespace std;

const int kMaxN = 1e5 + 5;

int n, a[kMaxN], b[kMaxN];

int vis[kMaxN], ans_flag;

char str_ans[kMaxN];

int dfs(char * ans, int step, int cur_node, bool flag)

{

if(cur_node < 1 || cur_node > n || vis[cur_node] > 1)

return 0;

if(vis[cur_node]) return 1;

if(cur_node == n) {

ans[step] = 0;

ans_flag = flag;

if(!flag) puts(ans);

return 2;

}

vis[cur_node] = 1;

ans[step] = 'a';

int ret = dfs(ans, step + 1, cur_node + a[cur_node], flag);

if(ret == 2) return 2;

ans[step] = 'b';

if(dfs(ans, step + 1, cur_node + b[cur_node], flag || ret==1) == 2)

return 2;

vis[cur_node] = 2;

return 0;

}

int main(){

//freopen("in.txt","r",stdin);

cin >> n;

for (int i = 1; i <= n; i ++)

scanf("%d", &a[i]);

for (int i = 1; i <= n; i ++)

scanf("%d", &b[i]);

memset(vis, 0, sizeof(vis));

if(dfs(str_ans, 0, 1, 0) != 2)

puts("No solution!");

else if(ans_flag){

puts("Infinity!");

}

return 0;

}

数码

时间限制:1秒

空间限制:32768K

题目描述

给定两个整数 l 和 r ,对于所有满足1 ≤ l ≤ x ≤ r ≤ 10^9 的 x ,把 x 的所有约数全部写下来。对于每个写下来的数,只保留最高位的那个数码。求1~9每个数码出现的次数。

输入描述:一行,两个整数 l 和 r (1 ≤ l ≤ r ≤ 10^9)。输出描述:输出9行。

第 i 行,输出数码 i 出现的次数。输入例子:1 4输出例子:421100000

题解:

首先,使用find_ans(n)计算1~n所有数的答案,那么最后的答案就是find_ans(r) - find_ans(l - 1)。

其次,要计算最高位为i的约数出现的次数。例如i=2,那么另cnt(x)为n以内约数包含x的数的个数,有:

ans[2] = cnt(2) + cnt(20) + cnt(21) + .... cnt(29) + cnt(200) + cnt(201) + ... 其中(x<=n)

所以我们分位数讨论

1位[i, i+1),2位[i*10, (i+1)*10), 3位[i*100, (i+1)*100)... ...     其中i取1~9。

我们知道,n以内包含约数x的自然数的个数为 n / x,即cnt(x) = n / x, 我们令ans[i]表示首位为i的答案,那么有:

ans[i] = sum{ sum{ n / x | i * 10^j <= x <= (i + 1) * 10^j} | 0 <= j <= 9}

上述步骤中可以看到对于每一个j, 即对于最高位为i且位数为(j+1)位的所有数x是连续的。 所以关键在于写一个函数,用于计算:

sigle_sum = (n / low) + (n / (low + 1)) + ... + (n / high) 其中 low = i * 10^j, high = (i + 1) * 10^j

可以看到上述计算单个答案sigle_sum 时,复杂度为O(10^j), 这对于一个位数较大(如j>=7)情况来说,枚举量依然非常巨大。

但是我们可以看到当j>=5时,low = i * 10^5, 有 n/low <= 10^4,所以我们可以枚举上述每一个式子的商(如商=x),再计算[low,high]区间中商为x的数有多少个,最后答案+ x * num(low, high, n, x),其中num(low, high, n, x)表示n/low, n/(low+1),,,n/(high)这些值中结果为x的个数,这个我们可以O(1)的计算出来。

最后计算sigle_sum总复杂度小于O(1e5)。

最后计算总答案复杂度:O(9 * 10 * 1e5),终于可以通过了~

#include

#include

#include

#include

#include

using namespace std;

typedef long long LL;

LL l, r;

LL a[10], b[10];

// calc (n / low) + (n / (low + 1)) + ... + (n / high)

LL find_ans(LL low, LL high, LL n)

{

if(high < low) return 0;

LL result = 0;

if(high - low < 1e5) for (int i = low; i <= high; i ++) {

result += n / i;

}

else {

LL l = n / high, r = n / low;

for (int i = l; i <= r; i ++) {

LL lb = max(n / (i + 1), low), rb = min(n / i, high);

if(n / rb == n / lb) rb ++;

result += (rb - lb) * i;

}

}

return result;

}

void find_ans(LL n, LL * ans)

{

memset(ans, 0, sizeof(LL) * 10);

if(!n) return ;

for (int i = 1; i <= 9; i ++) {

LL mul_num = 1;

for (int j = 0; j <= 9 && mul_num <= n; j ++) {

ans[i] += find_ans(i * mul_num, min((i + 1) * mul_num - 1, n), n);

mul_num *= 10;

}

}

}

int main(){

//freopen("in.txt","r",stdin);

cin >> l >> r;

find_ans(l - 1, a);

find_ans(r, b);

for (int i = 1; i <= 9; i ++)

cout << (b[i] - a[i]) << endl;

return 0;

}

围棋

题目描述

围棋是起源于中国有悠久历史的策略性棋类游戏。它的规则如下:

1. 棋盘19*19。

2. 棋子分黑白两色,双方各执一色。

3. 下法:每次黑或白着一子于棋盘的空点上。棋子下定后,不再向其他点移动。

4. 棋子的气:一个棋子在棋盘上,与它相邻的空点是这个棋子的“气”(这里相邻是指两个点有公共边)。 相邻的点上如果有同色棋子存在,这些棋子就相互连接成一个不可分割的整体,气合并计算。

相邻的点上如果有异色棋子存在,此处的气便不存在。

如果棋子所在的连通块失去所有的气,即为无气之子,不能在棋盘上存在。

5. 提子:把无气之子清理出棋盘的手段叫“提子”。提子有二种:

1) 着子后,对方棋子无气,应立即提取对方无气之子。

2) 着子后,双方棋子都呈无气状态,应立即提取对方无气之子。

6. 禁着点:棋盘上的任何一空点,如果某方在此下子,会使该子立即呈无气状态,同时又不能提取对方的棋子,这个点叫做“禁着点”,该方不能在此下子。

7. 禁止全局同形:无论哪一方,在成功进行了着子、提子操作后,棋盘局面不能和任何之前的局面相同。

你要做的是:输入一些操作,从空棋盘开始模拟这些操作。

对于每一步,若结果不正确,则输出对应的miss并且忽略这个操作,并在最后输出棋盘的局面。

输入描述:第一行,测试数据组数≤100第二行,每组测试数据,执行的步数 n ≤ 2000 然后 n 行 B x y W x y (1 ≤ x ≤ 19,1 ≤ y ≤ 19)其中,二元组 x,y 表示围棋棋盘上第 x 行第 y 列对应的点。输入数据保证是黑白轮流下的。输出描述:多行对于miss的情况,输出是哪一种错误格式,其中:miss 1 表示下的位置已经有棋了miss 2 表示违反规则6miss 3 表示违反规则7对于正常的操作,不用输出。最后输出最终盘面。“B表示黑子,W表示白子,如果是空点的话,就输出'.'字符。”输入例子:112B 1 3W 1 2B 2 4W 2 1B 1 1W 2 3B 3 3W 3 2B 1 1W 2 3B 2 2W 2 3对应的棋形是这样的:

95a82c13ba7864aa65127f3efbd4e85f.png

输出例子:miss 2miss 2miss 1miss 3.WB................WB.B................WB................................................................................................................................................................................................................................................................................................................................

题解:

这个比较纯粹,模拟每一次操作,然后判断是否合法,没太多可讲之处,纯粹是考察代码实现能力。当然我也只是完成了这道题而已啦,代码风格和可读性还比较低。返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值