微软2016校招笔试 第一场部分题目个人思路

嗯……第一场当时还不知道报名,第二场报上了,拿了250/400,果然分如其人……
这里包括的是第一场的ABC题,第二场的AB题的题解在另一篇(这些都是自己AC了的),第一场的D和第二场的C至今仍然在WA,不知道怎么回事,到时候也讲讲思路求指点吧。

A. Magic Box

这道题并不难做,唯一需要注意的是cx,cy和cz,以及任意两个量的差之间是没有前后关系的(这个事情样例里也告诉你了),所以比较简单的方法就是先把cx,cy,cz排序,然后根据输入串一个一个模拟,然后计算出两两之间的差,排序,比对就行了……

#include<iostream>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;

char str[30000];
int c[10];
int cnt[200];
int dif[10];

int main()
{
    cin>>c[1]>>c[2]>>c[3];
    cin>>str;
    int len = strlen(str);
    sort(&c[1], &c[4]);

    int i;
    int sum=0;
    int ans = 0;
    for(i=0;i<len;i++)
    {
        cnt[str[i]]++;
        sum++;
        ans = max(ans, sum);

        dif[1] = abs(cnt['R'] - cnt['Y']);
        dif[2] = abs(cnt['Y'] - cnt['B']);
        dif[3] = abs(cnt['B'] - cnt['R']);
        sort(&dif[1], &dif[4]);
        if(dif[1] == c[1] && dif[2] == c[2] && dif[3] == c[3])
        {
            memset(cnt, 0, sizeof(cnt));
            sum=0;
        }
    }
    cout<<ans<<endl;
    //system("pause");
    return 0;
}
B. Professor Q’s Software

这道题如果你注意到以下几点, 就并不难了:

  • 每个模块只会等一个信号,也就是说当模块发出一个信号的时候,我就能知道他激活了哪个模块,所以这很显然是一个图的关系,如果模块A能够放出一个信号1,模块B就是等信号1的,那么就可以画一条A-B的边。
  • 更关键的事情在于,你会发现等待相同信号的模块被激活的次数是一样的(如果模块A和模块B都等待1号信号,那么来一个信号的时候他们一定同时被激活),这也就是说等待信号相同的点是完全可以合并的,反正他们的答案是一样的;
  • 所以我们就可以用信号来命名节点了,这样就变成了一个很容易的拓扑图DP问题,因为题目明确说了不会有循环激活,意思就是这个图里不会有环。DP方程是:
    f[i]=Σ(f[k])+base[i]

    ,其中k代表所有和直接指向i的节点。意思就是每个节点的激活数量就是所有能激活他的节点的激活数量,加上最初的那组信号激活他的数量。
    由于每个点只有3条边,所以这个图十分稀疏, O(n+e) 可以轻松搞定。
  • 最后一个问题就是信号都是int,太大了存不下,但是只有10w个点,也就是说那么多数里面只有10w个有用的,那我们离散化一下就好了。这样,问题就全部解决了。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;

struct etype
{
    int num;
    int next;
};
etype node[1000000];
int p_nodes=0;
int edge[200000];

int t;
int n,m;
int base[200000];
int dp[200000];

int numbers[1000000];
int p_numbers=0;

int init_nums[600000];
struct Input
{
    int w;
    int cnt;
    int release[10];
};
Input input[200000];
int node_num[200000];

const int MOD = 142857;

void init()
{
    memset(node, 0, sizeof(node));
    p_nodes=0;
    memset(edge, 0, sizeof(edge));
    memset(base,0,sizeof(base));
    memset(dp, -1, sizeof(dp));
    memset(numbers, 0, sizeof(numbers));
    p_numbers=0;
}

int go(int now)
{
    if(dp[now]!=-1)
    {
        return dp[now];
    }

    dp[now] = base[now];
    int e;
    for(e=edge[now]; e!=0; e=node[e].next)
    {
        dp[now] = (dp[now] + go(node[e].num))%MOD;
    }
    return dp[now];
}

void new_edge(int k1, int k2)
{
    p_nodes++;
    node[p_nodes].num=k2;
    node[p_nodes].next = edge[k1];
    edge[k1] = p_nodes;
    return;
}

int find(int tar)
{
    int low=1, high=p_numbers;
    while(low<=high)
    {
        int mid=(low+high)/2;
        if(numbers[mid] == tar)
            return mid;
        if(numbers[mid] < tar)
            low = mid+1;
        else
            high = mid-1;
    }
    return -1;
}

void push(int x)
{
    numbers[++p_numbers] = x;
    return;
}

int main()
{
    scanf("%d", &t);
    for(int files=1; files<=t; files++)
    {
        init();
        scanf("%d %d", &n, &m);
        int i, j;
        for(i=1; i<=m; i++)
        {
            scanf("%d", &init_nums[i]);
            push(init_nums[i]);
        }
        for(i=1; i<=n; i++)
        {
            scanf("%d", &input[i].w);
            push(input[i].w);

            scanf("%d", &input[i].cnt);
            for(j=1; j<=input[i].cnt; j++)
            {
                scanf("%d", &input[i].release[j]);
                push(input[i].release[j]);
            }
        }

        sort(&numbers[1], &numbers[p_numbers+1]);
        p_numbers = unique(&numbers[1], &numbers[p_numbers+1]) - numbers - 1;

        for(i=1; i<=m; i++)
        {
            int mirror = find(init_nums[i]);
            base[mirror]++;
        }

        for(i=1; i<=n; i++)
        {
            node_num[i] = find(input[i].w);
        }

        for(i=1; i<=n; i++)
        {
            int now_node = node_num[i];
            for(j=1; j<=input[i].cnt; j++)
            {
                int now_target = find(input[i].release[j]);
                new_edge(now_target, now_node);
            }
        }

        for(i=1; i<=n;i++)
        {
            int now_node = node_num[i];
            if(dp[now_node]==-1)
            {
                dp[now_node] = go(now_node);
            }
        }
        for(i=1;i<=n;i++)
        {
            int now_node = node_num[i];
            printf("%d", dp[now_node]);
            if(i!=n)
                printf(" ");
        }
        printf("\n");
    }
    //system("pause");
    return 0;
}
C. Island Travel

这题我一开始没做出来,经过别人提示才会做的。一开始总是想各种排序之后怎么搞……
其实很简单,40%的数据只要裸Dijkstra就行了,但是你会发现其中很多边是没用的,事实上对于一个点来说,只有它的四个邻居,也就是他上下左右最近的那个点对他有意义。更远的点一定可以先走到你的邻居,再由你的邻居走到他,这样一定不会更差。
所以,虽然有10w个点,但是每个点只需要建4条边,一个十分稀疏的图,用SPFA或者是堆优化Dijkstra就能轻松搞了。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
using namespace std;

typedef long long LL;
typedef pair<LL, int> P;
const LL INF = 1e18;

int n;
struct etype
{
    int num;
    int len;
    int next;
};
etype node[1000000];
int p_nodes=0;
int edge[200000];
LL dis[200000];

priority_queue< P, vector<P>, greater<P> > q;

struct ptype
{
    int num;
    LL x;
    LL y;
};

ptype point[200000];

bool cmp1(const ptype &a, const ptype &b)
{
    return a.x<b.x;
}

bool cmp2(const ptype &a, const ptype &b )
{
    return a.y<b.y;
}

void new_edge(int k1, int k2, LL len)
{
    p_nodes++;
    node[p_nodes].num = k2;
    node[p_nodes].len = len;
    node[p_nodes].next = edge[k1];
    edge[k1] = p_nodes;
    return;
}

int main()
{
    scanf("%d", &n);
    int i;
    for(i=1; i<=n; i++)
    {
        scanf("%lld %lld", &point[i].x, &point[i].y);
        point[i].num=i;
    }

    for(i=1;i<=n;i++)
        dis[i] = INF;

    sort(&point[1], &point[n+1], cmp1);
    for(i=1; i<=n;i++)
    {
        if(i+1<=n)
        {
            new_edge(point[i].num, point[i+1].num, 
            min(abs(point[i].x - point[i+1].x), abs(point[i].y - point[i+1].y)));
        }
        if(i-1>=1)
        {
            new_edge(point[i].num, point[i-1].num, 
            min(abs(point[i].x - point[i-1].x), abs(point[i].y - point[i-1].y)));
        }
    }
    sort(&point[1], &point[n+1], cmp2);
    for(i=1; i<=n;i++)
    {
        if(i+1<=n)
        {
            new_edge(point[i].num, point[i+1].num, 
            min(abs(point[i].x - point[i+1].x), abs(point[i].y - point[i+1].y)));
        }
        if(i-1>=1)
        {
            new_edge(point[i].num, point[i-1].num, 
            min(abs(point[i].x - point[i-1].x), abs(point[i].y - point[i-1].y)));
        }
    }

    dis[1]=0;
    q.push(make_pair(0,1));
    while(!q.empty())
    {
        P now_pair = q.top();
        q.pop();

        int now = now_pair.second;
        if(dis[now] < now_pair.first)
            continue;

        int e = edge[now];
        for(e; e!=0; e=node[e].next)
        {
            if(dis[now] + node[e].len < dis[node[e].num])
            {
                dis[node[e].num] = dis[now] + node[e].len;
                q.push(make_pair(dis[node[e].num], node[e].num));
            }
        }
    }
    printf("%lld\n", dis[n]);
    //system("pause");
    return 0;

}
D. Recruitment

本题依然在WA,我的思路是这样的:
对男女分开DP,DP方程是

dp[i][rest][restbudget]=max(dp[i1][rest1][restbudgetv[i]],dp[i1][rest][restbudget])

意思就是每个人可以选或者不选,当然要控制一下条件什么的,对于所有不合法的状态都赋成-INF。
之后枚举给两边各自多少预算,由于之前已经求出了dp[n][rest][budget], 所以直接就可以知道给x预算的时候两边能选出多少value,计算和即可;

字典序的问题是这样解决的:用choice[i][rest][budget]表示面对这个情况的时候选没选第i个人,如果选了是1,不选是0,当选与不选的结果相等的时候,尽量不选,因为我们要把机会尽量留给前面的人;之后分配预算的时候,男女分别利用choice来找到自己选了哪些人,挑出来以后排个序,如果比当前最优解字典序更小,则取代之。

不知道什么地方有错,自己的数据和同学的数据都过了……

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;

int n,limit[2],b;
int dp[2][110][110][1100];
int choice[2][110][110][1100];
const int INF = 1<<30;

struct etype
{
    int gender;
    int value;
    int cost;
    int num;
};
etype ori[200], after[2][200];
int p[2];

int bestorder[200]={0};
int noworder[200]={0};

int bottom_cost[2];

bool cmp(const etype &a, const etype &b)
{
    return a.cost < b.cost;
}

void calc_bottomcost()
{
    etype tmp[2][200];
    memcpy(tmp, after, sizeof(after));

    int nowgender;
    for(nowgender=0; nowgender<=1; nowgender++)
    {
        sort(&tmp[nowgender][1], &tmp[nowgender][p[nowgender]+1], cmp);
        int i;
        for(i=1; i<=limit[nowgender]; i++)
        {
            bottom_cost[nowgender] += tmp[nowgender][i].cost;
        }
    }
    return;
}

void generate_order(int b0, int b1)
{
    int i,j;
    int p_noworder=0;
    for(int nowgender=0; nowgender<=1; nowgender++)
    {
        int now_x = limit[nowgender];
        int now_b = (nowgender == 0)? b0:b1; 
        for(i=p[nowgender]; i>=1; i--)
        {
            if(choice[nowgender][i][now_x][now_b] == 1)
            {
                now_x --;
                now_b -= after[nowgender][i].cost;
                noworder[++p_noworder] = after[nowgender][i].num;
            }
        }
    }
    sort(&noworder[1], &noworder[p_noworder+1]);
    return;
}

bool check()
{
    int i;
    for(i=1; i<=limit[0] + limit[1]; i++)
    {
        if(noworder[i] < bestorder[i])
            return true;
        else if(noworder[i] > bestorder[i])
            return false;
    }
    return false;
}

int main()
{
    scanf("%d %d %d %d", &n, &limit[0], &limit[1], &b);
    int i;
    for(i=1; i<=n;i++)
    {
        char tmp;
        scanf("\n%c %d %d", &tmp, &ori[i].value, &ori[i].cost);
        if(tmp == 'M')
        {
            ori[i].gender =0;
        }
        else
        {
            ori[i].gender=1;
        }
        ori[i].num=i;
        after[ori[i].gender][++p[ori[i].gender]] = ori[i];
    }

    calc_bottomcost();

    memset(dp,0,sizeof(dp));

    int j,k;
    for(int nowgender=0; nowgender<=1; nowgender++)
    {
        for(i=1; i<=p[nowgender];i++)
        {
            for(j=0; j<=limit[nowgender]; j++)
            {
                for(k=0; k<=b; k++)
                {
                    if(i<j)
                    {
                        dp[nowgender][i][j][k] = -INF;
                        continue;
                    }
                    int c1 = dp[nowgender][i-1][j][k];
                    int c2=-INF;
                    if(j-1 >= 0 && k - after[nowgender][i].cost >=0)
                    {
                        c2 = dp[nowgender][i-1][j-1][k-after[nowgender][i].cost] + after[nowgender][i].value;
                    }

                    //cout<<"nowgender "<<nowgender<<" i "<<i<<" j "<<j <<" k "<<k;
                    dp[nowgender][i][j][k] = max(c1,c2);
                    //cout<<" "<<dp[nowgender][i][j][k]<<"\n";

                    if(c1>=c2)
                        choice[nowgender][i][j][k] = 0;
                    else
                        choice[nowgender][i][j][k] = 1;

                    //cout<<"nowgender "<<nowgender<<" i "<<i<<" j "<<j <<" k "<<k;
                    //cout<<" "<<choice[nowgender][i][j][k]<<"\n";
                }
            }
        }
    }

    int max_value=0;
    int min_budget=INF;
    for(i=bottom_cost[0]; i<=b; i++)
    {
        for(j=bottom_cost[1]; j<=b-i; j++)
        {
            int now_value = dp[0][p[0]][limit[0]][i] + dp[1][p[1]][limit[1]][j];
            if(now_value > max_value)
            {
                max_value = now_value;
                min_budget = i+j;
                generate_order(i,j);
                memcpy(bestorder, noworder, sizeof(bestorder));
            }
            else if(now_value == max_value && i+j < min_budget)
            {
                min_budget = i+j;
                generate_order(i,j);
                memcpy(bestorder, noworder, sizeof(bestorder));
            }
            else if(now_value == max_value && i+j == min_budget)
            {
                generate_order(i,j);
                if(check())
                {
                    memcpy(bestorder, noworder, sizeof(bestorder));
                }
            }
        }
    }

    printf("%d %d\n", max_value, min_budget);
    for(i=1;i<=limit[0]+limit[1];i++)
    {
        printf("%d", bestorder[i]);
        if(i<limit[0]+limit[1])
            printf(" ");
    }
    printf("\n");
    system("pause");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值