微软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[i?1][rest?1][restbudget?v[i]],dp[i?1][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;
}
时间: 2024-11-03 09:28:32

微软2016校招笔试 第一场部分题目个人思路的相关文章

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

A. Lucky Substrings 这道题并不难,由于字符串长度只有100,那么它的子串肯定不超过1w个,枚举出所有字串都是没有问题的,至于检验一个子串里面不同的字母数量是不是斐波那契数,我们只需要事先把斐波那契数列小于1w的项都生成出来,然后枚举一个子串之后,统计出不同字母的数量(边找边统计,如果当前字母之前出现过就不加,如果没出现过就记住并+1),去这个里面找就行了.斐波那契数列推不了几项就到1w了-- 最后要字典序从小到大排列,并且还要去重,那就用string然后直接sort+uniq

一道校招笔试的C语言题目

今天想起一道原先参加校招的一道题目,其原理是C语言挺基础的东西,但很多人都答错了.     struct test {                 int a;         int *c;     };          struct test b;     b.a = 300;     b.c = 500;     printf("%d", b.a + b.c); 大家先想一下结果是多少,然后再运行一下验证验证.想一下是什么原理

微软苏州校招笔试 12月27日

题目1 : Lost in the City 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi gets lost in the city. He does not know where he is. He does not know which direction is north. Fortunately, Little Hi has a map of the city. The map can be considered as a grid

2016暑期选拔第一场20160709

A みねちゃんの修罗场 Time Limit: 5000 mSec    Memory Limit : 1024 KB  Problem Description みねちゃん是个成绩优秀大学二年级学生,本来是和像自己妹妹一般的青梅竹马一起过着普通的大学生活的,但某天却被校内公认的第一美人表白了.然而她的真实意图却是为了骗过众人而需要みねちゃん与她假扮情侣.被掌握了自己的某个"秘密"的みねちゃん被迫假扮"男友"这一角色--然而在此之后他的"未婚妻"也

【hihocoder】1237 : Farthest Point 微软2016校招在线笔试题

题目:给定一个圆,要你求出一个在里面或者在边上的整数点,使得这个点到原点的距离最大,如果有多个相同,输出x最大,再输出y最大. 思路:对于一个圆,里面整点个数的x是能确定的.你找到x的上下界就可以了.就是mix = ceil(x0-r)//因为是小的值,所以要向上取整.mxx=floor(x0+r)//大的值要向下取整 对于y.我们也能用欧股定理确定.y也是有一个范围.但是并不是所有y都要枚举的.明显.y的值是离圆心越远越好.所以对于每一个x而言只需要枚举最远的两个y值 #include <cs

[HiHoCoder]#1094 : Lost in the City 微软苏州校招笔试 12月27日

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi gets lost in the city. He does not know where he is. He does not know which direction is north. Fortunately, Little Hi has a map of the city. The map can be considered as a grid of N*M blocks. Each blo

hihocoder #1094 : Lost in the City微软苏州校招笔试 12月27日 (建图不大【暴力枚举】 子图的4种形态 1Y )

#1094 : Lost in the City 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi gets lost in the city. He does not know where he is. He does not know which direction is north. Fortunately, Little Hi has a map of the city. The map can be considered as a gri

微软2014编程之美初赛第一场——题目2 : 树

[来源] 题目2 : 树 [分析] 依据输入情况建立起树的模型.树的表示是一个表明父亲节点的数组.核心算法有两个: 计算某一节点的深度.用循环实现,一直向上找父亲节点,直到找到根节点.计算循环的次数即为深度. 计算某一节点的全部子节点.用递归实现. 本题在实现上节点的命名从0至N-1,与题目描写叙述不同. [代码] #include <iostream> #include <vector> using namespace std; vector<int> childre

2017年校招全国统一模拟笔试(第二场)编程题集合-牛客网

 2017年校招全国统一模拟笔试(第二场)编程题集合-牛客网 链接:https://www.nowcoder.com/questionTerminal/276712b113c6456c8cf31c5073a4f9d7来源:牛客网 牛牛有两个字符串(可能包含空格),牛牛想找出其中最长的公共连续子串,希望你能帮助他,并输出其长度. 输入描述: 输入为两行字符串(可能包含空格),长度均小于等于50. 输出描述: 输出为一个整数,表示最长公共连续子串的长度. 输入例子: abcde abgde 输出例子