2018腾讯暑假实习生后台开发岗线上笔试编程题题解

刷了两年多的题,终于开始动手写题解了,首发献给今天的腾讯笔试。
题目当初没截图存一下,靠记忆来一发。。。


第一题

题意

题目大致是说,给你两个整数n和m,取值范围的1~10^9,且n是(2*m)的倍数,然后有这样一个规律,数组从1开始,符号为负,每隔m个数就变一次符号。例如n取8,m取2,那么数组就是
-1 -2 3 4 -5 -6 7 8
题目要求求出这n个数的和。

思路

数据范围那么大,一般就是找规律。这题也是简单的找规律,多写几个就可以发现,每2*m个数的和就是m*m,同时n又是(2*m)的倍数,那就很好办了。结果就是m*m*(n/2/m),化简一下也行,当时约掉一个m,直接就上了。这里要注意,因为m最大可能是10^9,又要做乘法,所以得用long long,而且要先除再乘。

参考代码

#include <iostream>
#include <array>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <string>
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
#include <stack>

using std::cin; using std::cout;
using std::array;
using std::min; using std::max;
using std::string;
using std::set; using std::vector;
using std::queue; using std::stack;

typedef long long LL;

LL solve(LL n, LL m) {
    LL ans = m*m;
    ans = ans * (n/2/m);

    return ans;
}

int main() {
    std::ios::sync_with_stdio(false);

    LL n, m;

    cin >> n >> m;
    cout << solve(n, m) << "\n";

    return 0;
}

第二题

题意

题目是说呢,有x首长度为a的歌,以及y首长度为b的歌,然后想要用这么多首歌看能组合成多少个长度为k的歌单,在每个歌单中,每首歌只能出现一次,且不管歌的排列顺序,也就是直接组合就得了。因为结果可能较大,输出的歌单数对1000000007取模。
数据范围: k<=1000,a ,b 小于等于10, x,y小于等于100

样例:(第一个数是k,接下来依次是a, x, b, y,输出歌单数。)
输入:5 2 3 3 3
输出:9

思路

一开始想着dp,但是歌只能出现一次,dp感觉有点麻烦,就放弃了,改成研究一下样例,发现就是直接组合起来就行了。数据那么小,暴力一下,枚举0~x跟0~y的组合,刚好长度为k的就把两者的组合数相乘取模就好了。所以这道题实际上是考组合数取模。
一开始忘记组合数取模怎么搞,直接暴力求,因为精度一直卡60%,然后就强行在每次取组合数的时候分子分母约掉最大公约数,再取模,神奇地卡到了90%。。。。(其实做除法是不能取模的,卡就卡在这里了)笔试时没做完,现在补一下。

其实组合数画出来就是个杨辉三角:

null 0 1 2 3 4 5
0 1
1 1 1
2 1 2 1
3 1 3 3 1
4 1 4 6 4 1
5 1 5 10 10 5 1

所以直接递推+取模就可以出来了。

参考代码

#include <iostream>
#include <array>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <string>
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
#include <stack>

using std::cin; using std::cout;
using std::array;
using std::min; using std::max;
using std::string;
using std::set; using std::vector;
using std::queue; using std::stack;

typedef long long LL;

const LL MOD = 1000000007;
const int MAXN = 100+5;

LL comb[MAXN][MAXN];

void init() {
    for (int i=0; i<MAXN; ++i) {
        comb[i][0] = comb[i][i] = 1;
        for (int j=1; j<i; ++j) {
            comb[i][j] = comb[i-1][j] + comb[i-1][j-1];
            comb[i][j] %= MOD;
        }
    }
}

int main() {
    std::ios::sync_with_stdio(false);

    int k;
    int a, x, b, y;

    init();

    cin >> k;
    cin >> a >> x >> b >> y;

    LL ans = 0;
    LL val;
    for (int i=0; i<=x; ++i) {
        for (int j=0; j<=y; ++j) {
            if (i*a + j*b == k) {
                val = (comb[x][i] * comb[y][j]) % MOD;
                ans += val;
                ans %= MOD;
            }
        }
    }

    cout << ans << "\n";

    return 0;
}

第三题

题意

给一个n和m,范围是1~10^5,n表示机器人的个数,m表示任务数。每个机器人和任务都有两个参数,一个是时间,一个是等级。每个机器人只能做一个任务,且任务的时间不能超过机器人的时间,任务的等级不能超过机器人的等级。每完成一个任务,都能得到收益,收益是200*任务时间+3*任务等级。现在要求最多能够完成几个任务,以及最大收益是多少。

数据范围:时间<=1000,等级<=100(应该没记错吧)

思路

一开始呢,看到范围是10^5,想着按照出题人的习惯,大范围是数据一般都是一两个样例而已,就写了一发n^2暴力。机器人按等级、时间这个优先级正序排好,任务按收益、等级、时间这个优先级逆序排好。暴力交了上去,结果过了90%,我也是惊呆了。
之后改了一下,把暴力搜索机器人改了。因为等级的数据范围比较小,所以用multiset按机器人的等级分成多个容器,每个容器存该等级机器人的时间,最后二分查找就行了。这里不能用set,因为机器人的时间可能会有重复。(虽然我用set交了一发,也是过了90%,看来只有最后一个样例才有重复的时间。。。。)

参考代码

#include <iostream>
#include <array>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <string>
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
#include <stack>

using std::cin; using std::cout;
using std::array;
using std::min; using std::max;
using std::string;
using std::multiset; using std::vector;
using std::queue; using std::stack;
using std::sort; using std::lower_bound;

typedef long long LL;
const int MAXN = 1e5+5;

struct Work {
    int time, level;
};
Work robots[MAXN];
Work arg[MAXN];

LL money(const Work& a) {
    return 200*a.time + 3*a.level;
}

bool cmp_a(const Work& a, const Work& b) {
    LL ma = money(a);
    LL mb = money(b);

    if (ma == mb) {
        if (a.level == b.level)
            return a.time > b.time;
        else return a.level > b.level;
    } else {
        return ma > mb;
    }
}

bool cmp_b(const Work& a, const Work& b) {
    if (a.level == b.level) return a.time < b.time;
    else return a.level < b.level;
}

multiset<int> rob[105];

bool isOk(const Work& w, int n) {
    for (int i=w.level; i<=100; ++i) {
        auto idx = lower_bound(rob[i].begin(), rob[i].end(), w.time);
        if (idx != rob[i].end()) {
            rob[i].erase(idx);
            return true;
        }
    }

    return false;
}

int main() {
    int n, m;

    scanf("%d%d",&n, &m);
    for (int i=0; i<n; ++i) {
        scanf("%d%d", &robots[i].time, &robots[i].level);
        rob[robots[i].level].insert(robots[i].time);    
    }
    for (int i=0; i<m; ++i)
        scanf("%d%d", &arg[i].time, &arg[i].level);

    sort(robots, robots+n, cmp_b);
    sort(arg, arg+m, cmp_a);

    int cnt = 0;
    LL val = 0;
    for (int i=0; i<m; ++i) {
        if (isOk(arg[i], n)) {
            ++cnt;
            val += money(arg[i]);
        }
    }

    cout << cnt << " " << val << "\n";

    return 0;
}

猜你喜欢

转载自blog.csdn.net/feng964497595/article/details/79828150