腾讯 2018春招 笔试(安排机器;画家小Q;小Q的歌单;贪吃的小Q)

1 贪吃的小Q

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

输入描述:

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

输出描述:

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

输入例子1:

3 7

输出例子1:

4

//考察 二分法
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        getMax2( n, m);
    }

    static void getMax(int n,int m){
        //因为每天至少要吃1块巧克力,所以第1天最多吃M-(N-1)块巧克力
        int low=1,high=m-n+1;//因为第一天的在low-high之间,所以采用二分查找,时间复杂度到O(logn)
        while(low<=high){
            注意这里要向上取整;右移一位来除2
            int mid=(low+high+1)>>1;
            if(sum(mid,n)==m){
                System.out.println(mid);//如果第一天吃mid个巧克力,刚刚好吃完所有巧克力,那么直接返回
                return;
            }else if(sum(mid,n)>m){
                high=mid-1;
            }else{
                low=mid+1;
            }
        }
        //千万别忘记写这句
        System.out.println(high);
    }

    static int sum(int eat,int day){
        int sum=eat;
        for(int i=1;i<day;i++){
            eat=(eat+1)>>1;//向上取整
            sum+=eat;
        }
        return sum;
    }

2 翻转数列

小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 <= 10^9, 1 <= m), 并且满足n能被2m整除。

输出描述:

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

输入例子1:

8 2

输出例子1:

8

思路:
解题思路:一个数列共有n/2m组,每一组的和为m^2
所以,前n项和为:(n/2m)(m^2)=mn/2

注意不能用int,得用long类型

public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        long n=sc.nextInt();
        long m=sc.nextInt();
        long result=n*m/2;
        System.out.println(result);
    }

3 小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取模的结果。

输入例子1:

5
2 3 3 3

输出例子1:

9

思路:

先求出从i个数中选出j个数的组合数
注意,取出 j 个的排列组合是1: c[i][0]=1;

然后遍历取a的个数:从0开始,一直到x,计算能否符合题意,再求出次数

public class SongOfXiaoQ {

    static long[][] c=new long[105][105];
    static final int mod=1000000007;
    //从i个数中取j个 共有多少种取法,不考虑顺序位置
    private static void init(){
        //注意这里是1
        c[0][0]=1;
        for (int i=1;i<=100;i++){
            //注意这里是1
            c[i][0]=1;
            for(int j=1;j<=100;j++){
                long c1=c[i-1][j-1],c2=c[i-1][j];
                c[i][j]=(c1+c2)%mod;
            }
        }
    }

    public static void main(String[] args) {
        //初始化从i个数中取j个共有多少种取法,不考虑顺序问题
        init();
        Scanner scanner=new Scanner(System.in);
        int k=scanner.nextInt();
        int a=scanner.nextInt();
        int x=scanner.nextInt();
        int b=scanner.nextInt();
        int y=scanner.nextInt();
        long sum=0;

        for (int i=0;i<=x;i++){
            int bb=k-a*i;
            int chushub=bb/b;
            if(bb%b==0&&chushub>=0&&chushub<=y){
                sum+=c[x][i]*c[y][chushub];
            }
        }
        System.out.println(sum%mod);
    }

}

4 画家小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最少需要多少次操作完成绘画。

输入例子1:

4 4
YXXB
XYGX
XBYY
BXXY

输出例子1:

3

例子说明1:

XXXX
XXXX
XXXX
XXXX
->
YXXX
XYXX
XXYX
XXXY
->
YXXB
XYBX
XBYX
BXXY
->
YXXB
XYGX
XBYY
BXXY

public class PainterXiaoQ {
    static int n, m;
    static char[][] canvas = new char[60][60];//画布,因为画板宽高的范围是1-50
    static int min = 0;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        scanner.nextLine();
        for (int i = 0; i < n; i++) {
            String str = scanner.nextLine();
            char[] chars = str.toCharArray();
            for (int j = 0; j < m; j++) {
                canvas[i][j] = chars[j];
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int temp = canvas[i][j];
                if (temp == 'B') {
                    encounterB(i, j);
                }
                if (temp == 'Y') {
                    encounterY(i, j);
                }
                if (temp == 'G') {
                    encounterB(i, j);
                    encounterY(i, j);
                }
            }
        }
        System.out.println(min);
    }

    static void encounterB(int x, int y) {
        canvas[x][y] = 'X';
        int ii = x + 1, jj = y - 1;
        //注意while条件里,必须写(canvas[ii][jj] == 'B' || canvas[ii][jj] == 'G'),不然会死循环
        while (ii >= 0 && jj >= 0 && ii < n && jj < m && (canvas[ii][jj] == 'B' || canvas[ii][jj] == 'G')) {
            if (canvas[ii][jj] == 'B') {
                canvas[ii][jj] = 'X';
            } else {
                canvas[ii][jj] = 'Y';
            }
            ii++;
            jj--;
        }
        //不管while循环体有没有执行,min都要++
        min++;
    }

    static void encounterY(int x, int y) {
        int ii = x + 1, jj = y + 1;
        //注意while条件里,必须写(canvas[ii][jj] == 'B' || canvas[ii][jj] == 'G'),不然会死循环
        while (ii >= 0 && jj >= 0 && ii < n && jj < m && (canvas[ii][jj] == 'Y' || canvas[ii][jj] == 'G')) {
            if (canvas[ii][jj] == 'Y') {
                canvas[ii][jj] = 'X';
            } else {
                canvas[ii][jj] = 'B';
            }
            ii++;
            jj++;
        }
        //不管while循环体有没有执行,min都要++
        min++;
    }
}

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), 表示每个任务需要的完成时间和任务的难度等级。

输出描述:

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

输入例子1:

1 2
100 3
100 2
100 1

输出例子1:

1 20006

import java.util.*;

/**
 * @Auther: 
 * @Date: 2018/8/30 16:02
 * @Description: 安排机器
 */
public class ArrangeMachine {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        int m=scanner.nextInt();
        ArrayList<TimeAndDegree> arrayList1=new ArrayList<>(n);//记录机器信息
        for (int i=0;i<n;i++){
            TimeAndDegree ob=new TimeAndDegree(scanner.nextInt(),scanner.nextInt());
            arrayList1.add(ob);
        }

        ArrayList<TimeAndDegree> arrayList2=new ArrayList<>(m);//记录任务信息
        for (int i=0;i<m;i++){
            TimeAndDegree ob=new TimeAndDegree(scanner.nextInt(),scanner.nextInt());
            arrayList2.add(ob);
        }

        sort(arrayList1);
        sort(arrayList2);
        int num=0;//记录能完成的任务数量
        int profit=0;
        int[] degree=new int[105];//存放哪个等级被用了,等级是1-100,0位不占用
        for (int i=0, j=0;i<m&&j<n;i++){//i是任务的下标,j是机器的下标
            while (j<n&&arrayList1.get(j).getX()>=arrayList2.get(i).getX()){
                degree[arrayList1.get(j).getY()]++;
                j++;
            }
            for (int k=arrayList2.get(i).getY();k<=100;k++){//找时间刚好满足的时候,等级最小的机器
                if(degree[k]>0){
                    num++;
                    degree[k]--;
                    profit+=arrayList2.get(i).getX()*200+arrayList2.get(i).getY()*3;
                    break;
                }
            }
        }
        System.out.println(num+" "+profit);
    }

    //倒序排序,因为由效益公式可知,时间越长效益越大
    private static void sort(ArrayList<TimeAndDegree> arrayList1){
        Collections.sort(arrayList1, new Comparator<TimeAndDegree>() {
            @Override
            public int compare(TimeAndDegree a, TimeAndDegree b) {
                if(b.getX()==a.getX())
                    return b.getY()-a.getY();
                return b.getX()-a.getX();
            }
        });
    }
}

class TimeAndDegree{
    public TimeAndDegree(){}
    public TimeAndDegree(int x,int y){
        this.x=x;
        this.y=y;
    }

    private int x;//0-1000
    private int y;//0-100

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值