2023.4.11 蚂蚁后端笔试

蚂蚁C++后端暑期实习4.11 笔试题:

1. 签到题:给一个数组,找有多少个出现数量是素数的素数。

2. 给一个n*m的网格(n,m <= 1e9),在每一个点你可以往左上,左下,右上,右下走,当遇到四个顶点时会原路反弹,在遇到不是顶点的边界时90度反弹,类似一个反射面,给定初始位置和出发方向,问走多少步回到起点。

Sample Input 1
5 7 1 7 DL
Sample Output 1
24

Sample Input 2
3 3 1 2 DR
Sample Output 2
4

3. 给一个01串,长度2e5,现在需要构造一个等长度的小写字母的字符串,要求所有相同字母对应位置的01串的数都同为0或同为1,比如01串为010,字符串可以是aba,abc,但不能是aaa,因为a对应了0和1。让你构造一个这样的字符串,使得最多数量的字母最少。

Sample Input
01010101010101010101010101
Sample Output
anbocpdqerfsgthuivjwkxlymz

题解:

1. 签到

2. 把边界当成镜子,然后遇到边界不会反射,而是继续直走,相当于把原来的矩形翻转180度,这样当走到经过一系列翻转后的起点就相当于回到起点,构造二元一次方程使用扩展欧几里得算法求解即可。由于答案可以超过int范围,暴力很容易超时。

#include <bits/stdc++.h>
using namespace std;

int n, m, x, y, start_x, start_y;
char s[3];

int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1;
        y=0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y = y - a / b * x;
    return d;
}

//求解方程ax + by = c的最小正整数解
int solve(int a, int b, int c) {
    int gcd = exgcd(a, b, x, y); 
    if(c % gcd != 0) return -1;
    x = x * (c / gcd);
    x = x % (abs(b / gcd));
    if(x <= 0) x = x + abs(b / gcd);
    return x;
}

int main() {
    scanf("%d %d %d %d %s", &n, &m, &start_x, &start_y, s);

    //通过把图翻转将不同方向统一到DR方向处理
    if(s[0] == 'U' && s[1] == 'R') {
        start_x = n - start_x + 1;
    }else if(s[0] == 'U' && s[1] == 'L') {
        start_x = n - start_x + 1;
        start_y = m - start_y + 1;
    }else if(s[0] == 'D' && s[1] == 'L') {
        start_y = m - start_y + 1;
    }
    long long ans = 2e18;
    //printf("%d %d\n", start_x, start_y);

    //四种类型的点进行分别处理
    int a = 2 * (n - 1), b = -2 * (m - 1), c = 0;
    int p = solve(a, b, c);
    if(p != -1) ans = min(ans, 2LL * p * (n - 1));

    a = 2 * (n - 1), b = -2 * (m - 1), c = -2 * start_y + 2;
    p = solve(a, b, c);
    if(p != -1) ans = min(ans, 2LL * p * (n - 1));

    a = 2 * (n - 1), b = -2 * (m - 1), c = 2 * start_x - 2;
    p = solve(a, b, c);
    if(p != -1) ans = min(ans, 2LL * p * (n - 1) - 2LL * start_x + 2);

    a = 2 * (n - 1), b = -2 * (m - 1), c = 2 * start_x - 2 * start_y;
    p = solve(a, b, c);
    if(p != -1) ans = min(ans, 2LL * p * (n - 1) - 2 * start_x + 2);

    printf("%lld\n", ans == 2e18 ? -1 : ans);
}

3. 可以从小到大枚举这个最高的高度,对字母a - z依次填充,尽量按照枚举的高度填,并且使得0的字母的数量总和为01串的0的数量,1的为1的,如果可以,那更大的高度也一定可以,所以符合二分法,但没有必要,直接暴力搜就完事了。

#include <bits/stdc++.h>
using namespace std;

char s[200005];
int cnt01[2] = {0}, alpha[26], mark[26];
queue<char> avail[2];

int main() {
    scanf("%s", s);
    int n = strlen(s), ans = 1e9;
    for(int i = 0; i < n; i++) cnt01[(int)(s[i] - '0')]++;
    for(int max_height = 1; max_height <= n; max_height++) {
        int sum0 = 0, sum1 = 0;
        for(int i = 0; i < 26; i++) {
            if(sum0 < cnt01[0]) {
                mark[i] = 0;
                alpha[i] = min(cnt01[0] - sum0, max_height);
                sum0 += min(cnt01[0] - sum0, max_height);
            }else{
                mark[i] = 1;
                alpha[i] = min(cnt01[1] - sum1, max_height);
                sum1 += min(cnt01[1] - sum1, max_height);
            }
        }
        if(sum0 == cnt01[0] && sum1 == cnt01[1]) break;
    } 
    for(int i = 0; i < 26; i++) {
        for(int j = 0; j < alpha[i]; j++) {
            avail[mark[i]].push((char)('a' + i));
        }
    }
    for(int i = 0; i < n; i++) {
        printf("%c", avail[(int)(s[i] - '0')].front());
        avail[(int)(s[i] - '0')].pop();
    }
    printf("\n");
}

#软件开发2023笔面经#

#软件开发2023笔面经#
全部评论
第三题还是看不懂啊大佬
点赞 回复 分享
发布于 2023-04-13 10:21 四川

相关推荐

头像
09-29 16:18
门头沟学院 Java
点赞 评论 收藏
分享
我是小红是我:学校换成中南
点赞 评论 收藏
分享
7 18 评论
分享
牛客网
牛客企业服务