微软2016校园招聘笔试(第一场) Professor Q's Software & Recruitment

来源:互联网 发布:python服务器搭建 编辑:程序博客网 时间:2024/05/18 03:38

为什么只有这两个题的题解?因为师兄只让我看了这两个题。。

题目链接:

Professor Q's Software 

Recruitment

#1136 : Professor Q's Software

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

Professor Q develops a new software. The software consists of N modules which are numbered from 1 to N. The i-th module will be started up by signal Si. If signal Si is generated multiple times, the i-th module will also be started multiple times. Two different modules may be started up by the same signal. During its lifecircle, the i-th module will generate Ki signals: E1, E2, ..., EKi. These signals may start up other modules and so on. Fortunately the software is so carefully designed that there is no loop in the starting chain of modules, which means eventually all the modules will be stoped. Professor Q generates some initial signals and want to know how many times each module is started.

输入

The first line contains an integer T, the number of test cases. T test cases follows.

For each test case, the first line contains contains two numbers N and M, indicating the number of modules and number of signals that Professor Q generates initially.

The second line contains M integers, indicating the signals that Professor Q generates initially.

Line 3~N + 2, each line describes an module, following the format S, K, E1, E2, ... , EK. S represents the signal that start up this module. K represents the total amount of signals that are generated during the lifecircle of this module. And E1 ... EK are these signals.

For 20% data, all N, M <= 10
For 40% data, all N, M <= 103
For 100% data, all 1 <= T <= 5, N, M <= 105, 0 <= K <= 3, 0 <= S, E <= 105.

Hint: HUGE input in this problem. Fast IO such as scanf and BufferedReader are recommended.

输出

For each test case, output a line with N numbers Ans1, Ans2, ... , AnsN. Ansi is the number of times that the i-th module is started. In case the answers may be too large, output the answers modulo 142857 (the remainder of division by 142857).

样例输入
33 2123 256123 2 456 256456 3 666 111 256256 1 903 1100100 2 200 200200 1 300200 05 111 2 2 32 2 3 43 2 4 54 2 5 65 2 6 7
样例输出
1 1 31 2 21 1 2 3 5

开始想dp或者数据结构胡搞。。后来发现是个拓扑排序裸题。。

思路:

分析题目后发现每个点集是个有向无环图,所以直接拓扑排序得出点的顺序,因为排序后相连点的顺序在该点之后,所以可以dp一下。

需要注意的是,虽然dfs拓扑排序复杂度是O(VE)的,但是E是和每个点的相连的边,题目里说了最多3条边,所以可以用这种方法,而O(V^2)的拓扑排序就显然不行。

AC代码:

#include <cstdio>#include <cstring>#include <vector>#include <stack>using namespace std;const int MOD = 142857;const int M = 100020;int sig[M], idx[M];bool vis[M];vector<int> module[M];stack<int> stk;bool dfs(int now) {//dfs    vis[now] = -1;    for(int i = 0; i < module[now].size(); i++) {        if(vis[module[now][i]] == -1) return false;        else if(vis[module[now][i]] == 0) {            dfs(module[now][i]);        }    }    vis[now] = 1;    stk.push(now);    return true;}bool toposort() {//拓扑排序    memset(vis, 0, sizeof vis);    for(int i = 0; i < M; i++) {        if(vis[i] == 0) {            if(dfs(i) == false) return false;        }    }    return true;}main() {    int T;    scanf("%d", &T);    while(T--) {        memset(sig, 0, sizeof sig);        int n, m;        scanf("%d %d", &n, &m);        for(int i = 0; i < n; i++) module[i].clear();        for(int i = 0; i < m; i++) {            int a;            scanf("%d", &a);            sig[a]++;        }        for(int i = 0; i < n; i++) {            int signal, p;            scanf("%d %d", &signal, &p);            idx[i] = signal;            for(int j = 0; j < p; j++) {                int a;                scanf("%d", &a);                module[signal].push_back(a);            }        }        if(toposort()) {//dp            while(!stk.empty()) {                int signal = stk.top();                stk.pop();                for(int i = 0; i < module[signal].size(); i++) {                    sig[module[signal][i]] += sig[signal];                    sig[module[signal][i]] %= MOD;                }            }        }        printf("%d", sig[idx[0]]);        for(int i = 1; i < n; i++)            printf(" %d", sig[idx[i]]);        putchar('\n');    }}

#1137 : Recruitment

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

A company plans to recruit some new employees. There are N candidates (indexed from 1 to N) have taken the recruitment examination. After the examination, the well-estimated ability value as well as the expected salary per year of each candidate is collected by the Human Resource Department.

Now the company need to choose their new employees according to these data. To maximize the company's benefits, some principles should be followed:

1. There should be exactly X males and Y females.

2. The sum of salaries per year of the chosen candidates should not exceed the given budget B.

3. The sum of ability values of the chosen candidates should be maximum, without breaking the previous principles. Based on this, the sum of the salary per year should be minimum.

4. If there are multiple answers, choose the lexicographically smallest one. In other words, you should minimize the smallest index of the chosen candidates; If there are still multiple answers, then minimize the second smallest index; If still multiple answers, then minimize the third smallest one; ...

Your task is to help the company choose the new employees from those candidates.

输入

The first line contains four integers N, X, Y, and B, separated by a single space. The meanings of all these variables are showed in the description above. 1 <= N <= 100, 0 <= X <= N, 0 <= Y <= N, 1 <= X + Y <= N, 1 <= B <= 1000.

Then follows N lines. The i-th line contains the data of the i-th candidate: a character G, and two integers V and S, separated by a single space. G indicates the gender (either "M" for male, or "F" for female), V is the well-estimated ability value and S is the expected salary per year of this candidate. 1 <= V <= 10000, 0 <= S <= 10.

We assure that there is always at least one possible answer.

输出

On the first line, output the sum of ability values and the sum of salaries per year of the chosen candidates, separated by a single space.

On the second line, output the indexes of the chosen candidates in ascending order, separated by a single space.

样例输入
4 1 1 10F 2 3M 7 6M 3 2F 9 9
样例输出
9 91 2
这个题显然就是个dp,关键在dp的技巧上。

思路:男女分别dp,然后匹配。

做两个dp,dpf[i][j]表示所有女性中选i个,工资为j时的价值,dpm[i][j]表示所有男性中选i个,工资为j时的价值;fidx[i][j][0],i j表示之前的dpf[i][j],0是所有应聘人的前50个,1是后50个,这是个long long数组, 利用位运算来标记对应i j选了哪些人,midx同理。

设要选female个女性,male个男性,对所有的dpf[female][i]和dpm[male][j]匹配,根据题意选出B以下价值最大工资最低字典序最靠前的。

AC代码:

#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;int dpf[105][1005], dpm[105][1005];unsigned long long fidx[105][1005][2];unsigned long long midx[105][1005][2];main() {    int n, male, female, b;    while(~scanf("%d %d %d %d", &n, &male, &female, &b)) {        memset(dpf, -1, sizeof dpf);        memset(dpm, -1, sizeof dpm);        memset(fidx, 0, sizeof fidx);        memset(midx, 0, sizeof midx);        dpf[0][0] = dpm[0][0] = 0;        int cntm = 0, cntf = 0, sum = 0;        for(int i = 1; i <= n; i++) {            char str[2];            int v, c;            scanf("%s %d %d", str, &v, &c);            sum += c;            sum = min(sum, b);            if(str[0] == 'F') {                cntf++;                cntf = min(cntf, female);                for(int j = cntf; j >= 1; j--) {//dp女性                    for(int k = sum; k >= c; k--){                        if(dpf[j - 1][k - c] < 0) continue;                        if(dpf[j - 1][k - c] + v > dpf[j][k]) {                            dpf[j][k] = dpf[j - 1][k - c] + v;                            fidx[j][k][0] = fidx[j - 1][k - c][0], fidx[j][k][1] = fidx[j - 1][k - c][1];                            if(i - 1 < 50) fidx[j][k][0] |= 1LL << (i - 1);                            else fidx[j][k][1] |= 1LL << (i - 1 - 50);                        //    printf("dpf %d %d %d %d %d\n", j, k, i, fidx[j][k][0], fidx[j][k][1]);                        }                    }                }            }            else {                cntm++;                cntm = min(cntm, male);                for(int j = cntm; j >= 1; j--) {//dp男性                    for(int k = sum; k >= c; k--){                        if(dpm[j - 1][k - c] < 0) continue;                        if(dpm[j - 1][k - c] + v > dpm[j][k]) {                            dpm[j][k] = dpm[j - 1][k - c] + v;                            midx[j][k][0] = midx[j - 1][k - c][0], midx[j][k][1] = midx[j - 1][k - c][1];                            if(i - 1< 50) midx[j][k][0] |= 1LL << (i - 1);                            else midx[j][k][1] |= 1LL << (i - 1 - 50);                          //  printf("dpf %d %d %d %I64u %0x\n", j, k, i, midx[j][k][0], midx[j][k][1]);                        }                    }                }            }        }        int ansv = -1, ansc = 0;        unsigned long long idx[2] = {0};        for(int i = 0; i <= b; i++) {//男女匹配,选取最符合题意的组合           if(dpf[female][i] == -1) continue;            for(int j = 0; j <= b - i; j++) {                if(dpm[male][j] == -1) continue;                if(dpf[female][i] + dpm[male][j] > ansv) {                    ansv = dpf[female][i] + dpm[male][j];                    ansc = i + j;                    idx[0] = fidx[female][i][0] | midx[male][j][0];                    idx[1] = fidx[female][i][1] | midx[male][j][1];                }                else if(dpf[female][i] + dpm[male][j] == ansv && ansc > i + j) {                    ansc = i + j;                    idx[0] = fidx[female][i][0] | midx[male][j][0];                    idx[1] = fidx[female][i][1] | midx[male][j][1];                }                else if(dpf[female][i] + dpm[male][j] == ansv && ansc == i + j) {                    int idx0 = fidx[female][i][0] | midx[male][j][0];                    int idx1 = fidx[female][i][1] | midx[male][j][1];                    if(idx[0] > idx0) {                        idx[0] = idx0, idx[1] = idx1;                    }                    else if(idx[0] == idx[0] && idx[1] > idx1) {                        idx[0] = idx0, idx[1] = idx1;                    }                }            }        }        printf("%d %d\n", ansv, ansc);//        printf("%I64u %0x\n", idx[0], idx[1]);        bool flag = false;        for(int i = 1; i <= 50; i++) {            if(idx[0] & 1) {                if(flag) printf(" ");                flag = true;                printf("%d", i);            }            idx[0] >>= 1;        }        for(int i = 51; i <= 100; i++) {            if(idx[1] & 1) {                if(flag) printf(" ");                flag = true;                printf("%d", i);            }            idx[1] >>= 1;        }        putchar('\n');    }}



0 0
原创粉丝点击