腾讯2018春招技术类编程题汇总

1 翻转数列

题目描述:

  小Q定义了一种数列称为翻转数列:
  给定整数n和m, 满足n能被2m整除。对于一串连续递增整数数列1, 2, 3, 4…, 每隔m个符号翻转一次, 最初符号为’-‘;。
  例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
  而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
  小Q现在希望你能帮他算算前n项和为多少。

输入描述:

  输入包括两个整数n和m(2 <= n <= 109, 1 <= m), 并且满足n能被2m整除。

输出描述:

  输出一个整数, 表示前n项和。

题目分析:


  根据题目的含义及输入要求可知,输入数据中正数与复数的个数相等,且总是以m个数据为一组进行符号翻转,很容易找出规律,即:

  从数据开始,以2m为单位从前往后数,每相邻2m个数的和均相等,且等于m2,且所有数据一共有n / 2m个这样的组。

代码实现:

#include <iostream>
using namespace std;
int main(){
    long int n, m;
    cin >> n >> m;
    cout << n / m / 2 * m * m << endl;
    return 0;
}

2 纸牌游戏

题目描述:


  牛牛和羊羊正在玩一个纸牌游戏。这个游戏一共有n张纸牌, 第i张纸牌上写着数字ai
  牛牛和羊羊轮流抽牌, 牛牛先抽, 每次抽牌他们可以从纸牌堆中任意选择一张抽出, 直到纸牌被抽完。
  他们的得分等于他们抽到的纸牌数字总和。
  现在假设牛牛和羊羊都采用最优策略, 请你计算出游戏结束后牛牛得分减去羊羊得分等于多少。

输入描述:

  输入包括两行。
  第一行包括一个正整数n(1 <= n <= 105),表示纸牌的数量。
  第二行包括n个正整数ai(1 <= ai <= 109),表示每张纸牌上的数字。

输出描述:

  输出一个整数, 表示游戏结束后牛牛得分减去羊羊得分等于多少。

题目分析:

  根据题意可知,二人每次均取剩下的数牌中最大的一张,因此,将扑克牌从小到大排序,从后往前依次做加减运算即可得到最终答案。

代码实现:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int n, sub = 0;
    cin >> n;
    vector<int>arr(n, 0);
    for(int i = 0; i < n; i++) cin >> arr[i];
    sort(arr.begin(), arr.end());
    while(n){
        sub += arr[--n];
        if(n) sub -= arr[--n];
    }
    cout << sub << endl;
    return 0;
}

3 贪吃的小Q

题目描述:

  小Q的父母要出差N天,走之前给小Q留下了M块巧克力。小Q决定每天吃的巧克力数量不少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有巧克力吃,请问他第一天最多能吃多少块巧克力

输入描述:

  每个输入包含一个测试用例。
  每个测试用例的第一行包含两个正整数,表示父母出差的天数N(N<=50000)和巧克力的数量M(N<=M<=100000)。

输出描述:

  输出一个数表示小Q第一天最多能吃多少块巧克力。

题目分析:

  假设第一天最多吃max块巧克力,从max开始验证,直到找到正确结果。

代码实现:

#include <iostream>
#include <cmath>
using namespace std;
int isRight(int n, int m, int max){
    while(n && m && max != 1){
        n--, m -= max;
        if(m < n) return false; 
        max = ceil(max / 2.0);
    }
    return true;
}
int main(){
    int n, m, max;
    cin >> n >> m;
    for(max = m; ; max--) if(isRight(n, m, max)) break;
    cout << max << endl;
    return 0;
}

4 小Q的歌单

题目描述:

  小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。

输入描述:

  每个输入包含一个测试用例。
  每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000)。
  接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数量Y(Y<=100)。保证A不等于B。

输出描述:

  输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。

题目分析:

  本题首先需要确定多少个A和多少个B能组成和为K的数,然后求C(X, A) 和C(Y, B)的积,C(X, A)为从X个数中抽取A个数的种类。

代码实现:

#include <iostream>
#define mode 1000000007
using namespace std;
int main() {
    long long CMN[102][102];
    for (int i = 0; i < 102; i++) CMN[i][0] = 1, CMN[i][i] = 1;
    for (int i = 1; i < 102; i++)
        for (int j = 1; j < i; j++)
            CMN[i][j] = (CMN[i - 1][j - 1] + CMN[i - 1][j]) % mode;
    int k, a, ia, b, ib;
    long long llSum = 0;
    cin >> k >> a >> ia >> b >> ib;
    int step = a > b ? a : b;
    for (int i = 0; i <= ia;) {
        if (i * a <= k && (k - i * a) % b == 0 && (k - i * a) / b <= ib) {
            llSum = (llSum + (CMN[ia][i] * CMN[ib][(k - i * a) / b]) % mode) % mode;
            i += step;
        }
        else i++;
    }
    cout << llSum << endl;
    return 0;
}

5 安排机器

题目描述:

  小Q的公司最近接到m个任务, 第i个任务需要xi的时间去完成, 难度等级为yi
  小Q拥有n台机器, 每台机器最长工作时间zi, 机器等级wi
  对于一个任务,它只能交由一台机器来完成, 如果安排给它的机器的最长工作时间小于任务需要的时间, 则不能完成,如果完成这个任务将获得200 * xi + 3 * yi收益。
  对于一台机器,它一天只能完成一个任务, 如果它的机器等级小于安排给它的任务难度等级, 则不能完成。
  小Q想在今天尽可能的去完成任务, 即完成的任务数量最大。如果有多种安排方案,小Q还想找到收益最大的那个方案。小Q需要你来帮助他计算一下。

输入描述:

  输入包括N + M + 1行,
  输入的第一行为两个正整数n和m(1 <= n, m <= 100000), 表示机器的数量和任务的数量。
  接下来n行,每行两个整数zi和wi(0 < zi < 1000, 0 <= wi <= 100), 表示每台机器的最大工作时间和机器等级。
  接下来的m行,每行两个整数xi和yi(0 < xi < 1000, 0 <= yi<= 100), 表示每个任务需要的完成时间和任务的难度等级。

输出描述:

  输出两个整数, 分别表示最大能完成的任务数量和获取的收益。

题目分析:

  设有机器 M={m1,m2,...,mn} M = { m 1 , m 2 , . . . , m n } ,其中第i个机器对应的等级和时间分别为 mil,mit m i l , m i t ;有任务 T={t1,t2,...,tm} T = { t 1 , t 2 , . . . , t m } ,其中任务第i个任务对应的等级和时间分别为 til,tit t i l , t i t 现在假设机器和任务都是按照工作时间非递增排序的,且相同的工作时间的机器或任务按等级非递增排序。
  此外,我们还需要一个辅助数组 lev[101] l e v [ 101 ] ,我们初始化 lev l e v 中每个元素均为0,结合下面的伪代码,我们就会明白 lev l e v 的作用。
   for i=0,j=0;i<m;i++ f o r   i = 0 , j = 0 ; i < m ; i + +
     for ;j<n f o r   ; j < n && mjt>til;j++ m j t > t i l ; j + +
       lev[mjl]++ l e v [ m j l ] + +
     for k=til;k<=100;k++ f o r   k = t i l ; k <= 100 ; k + +
       if lev[k] i f   l e v [ k ]
         num++,gain+=200tit+3til n u m + + , g a i n + = 200 ∗ t i t + 3 ∗ t i l
         break b r e a k
   cout<<num<<""<<gain<<endl; c o u t << n u m <<""<< g a i n << e n d l ;

代码实现:

#include <iostream>
#include <algorithm>
using namespace std;
struct Node { int l, t; };
bool cmp(Node n1, Node n2) {
    if (n1.t == n2.t) return n1.l >= n2.l;
    return n1.t >= n2.t;
}
int main() {
    int n, m, num = 0;
    long long sum = 0;
    cin >> n >> m;
    Node*M = (Node*)malloc(sizeof(Node)*n);
    Node*T = (Node*)malloc(sizeof(Node)*m);
    int lev[101] = { 0 };
    for (int i = 0; i < n; i++) cin >> M[i].t >> M[i].l;
    for (int i = 0; i < m; i++) cin >> T[i].t >> T[i].l;
    sort(M, M + n, cmp);
    sort(T, T + m, cmp);
    for (int i = 0, j = 0; i < m; i++) {
        for (; j < n && M[j].t >= T[i].t; j++)
            lev[M[j].l]++;
        for (int k = T[i].l; k <= 100; k++) 
            if (lev[k]) {
                num++, sum += 200 * T[i].t + 3 * T[i].l;
                lev[k]--;
                break;
            }
    }
    cout << num << " " << sum << endl;
    return 0;
}

6 画家小Q

题目描述:

  画家小Q又开始他的艺术创作。小Q拿出了一块有NxM像素格的画板, 画板初始状态是空白的,用’X’表示。
  小Q有他独特的绘画技巧,每次小Q会选择一条斜线, 如果斜线的方向形如’/’,即斜率为1,小Q会选择这条斜线中的一段格子,都涂画为蓝色,用’B’表示;如果对角线的方向形如’\’,即斜率为-1,小Q会选择这条斜线中的一段格子,都涂画为黄色,用’Y’表示。
  如果一个格子既被蓝色涂画过又被黄色涂画过,那么这个格子就会变成绿色,用’G’表示。
  小Q已经有想画出的作品的样子, 请你帮他计算一下他最少需要多少次操作完成这幅画。

输入描述:

  每个输入包含一个测试用例。
  每个测试用例的第一行包含两个正整数N和M(1 <= N, M <= 50), 表示画板的长宽。
  接下来的N行包含N个长度为M的字符串, 其中包含字符’B’,’Y’,’G’,’X’,分别表示蓝色,黄色,绿色,空白。整个表示小Q要完成的作品。

输出描述:

  输出一个正整数, 表示小Q最少需要多少次操作完成绘画。

题目分析:

  我们首先以一个简单的例子进行模拟解题过程:



X


输入案例:
XYGB
XYGX
BBYX
XYGB






求解步骤:
0134
4555
6666
6678

  通过上面的求解步骤,我们很容易找出解题思路:从上往下,从左往右遍历画板像素,根据当前像素的类型与其左上和右上的类型判断操作次数增加值。

代码实现:

#include <iostream>
using namespace std;
int main() {
    int n, m, sum = 0;
    cin >> n >> m;
    char str[55][55];
    for (int i = 0; i < n; i++) cin >> str[i];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (str[i][j] == 'B') {
                if (i == 0 || j == m - 1 ||
                    (str[i - 1][j + 1] != 'B' && str[i - 1][j + 1] != 'G'))
                    sum++;
            }
            else if (str[i][j] == 'Y') {
                if (i == 0 || j == 0 ||
                    (str[i - 1][j - 1] != 'Y' && str[i - 1][j - 1] != 'G'))
                    sum++;
            }
            else if (str[i][j] == 'G') {
                if (i == 0) {sum += 2; continue;}
                if (j == 0) sum++;
                if (j == m - 1) sum++;
                if (j > 0 && str[i - 1][j - 1] != 'Y' && str[i - 1][j - 1] != 'G') sum++;
                if (j < m - 1 && str[i - 1][j + 1] != 'B' && str[i - 1][j + 1] != 'G') sum++;
            }
        }
    }
    cout << sum << endl;
    return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值