2017微软秋季校园招聘在线编程笔试
2016-10-11 10:41
465 查看
别的不多说了,记录一下题目吧。找工作有很大一部分因素是缘分,莫强求,保持好心态~
只A了前三道:
第一题:
题意:给出n个数(n≤1000000),可以任意选择两个相邻的数字,如果它们相加的和是奇数,那么可以将这两个数删除。问最后可能剩下的最少的数的数量。
思路:细想可知最后剩下的数的数量是确定的。比如考虑有x个奇数,y个偶数(x>y),那么必然存在某个偶数和奇数相邻可删除。所以数量少的必定最后会全部被删除。最后的答案也就是奇数的数量和偶数数量之差的绝对值咯。
代码如下:
第二题:
题意:给出一个长度为n(n<100000)的只包含小写字符的字符串s[0...n-1],再给出m(m<=200)个字符对(如:ab),表示ab和ba不能出现在串中(后文称这个不能出现的集合为黑名单。问最少删除几个字符能够使得输入串是合法的?
思路:只需求合法的串的最长可能。明显思路是dp。一个显然的一维dp是设dp[x]表示考虑前s[0...x]中,且最后一个字符必须是s[x]的情况下的最长可能。那么dp[x]=max(dp[j]+1),0<=j<=x-1且(s[j],s[x])不出现在黑名单中。两点说明:第一,dp的值不是递增的,所以不能从大到小遍历j,找到第一个(s[j],s[x])不在黑名单中就退出。这一点可以考虑如下例子:acccbd,黑名单是(c,b)。第二:这个dp 的复杂度显然是O(n^2),会超时。
还是考虑上述dp,有没有考虑重复的情况呢?其实是有的,在遍历j的过程中,s[j]处可能出现多个相同的字符的情况,实际上这只需要考虑最长的那个即可。这给出了一个启示:只需要维护以特定字符结尾的最长的数量即可。所以dp设计为:dp(i,j)表示考虑前i的字符的子串且最后一个字符为j(0<=j<=25)的最长可能。那么实际上每遇到一个新的s[i],只需要更新以s[i]为最后一个字符的情况,其他的情况都未变。状态方程为:如果j表示的是s[i]的字符:那么dp[i][j] = max(dp[i-1][k]+1),0<=k<=25且(('a'+k),
s[i])不出现在黑名单中;否则dp[i][j] = dp[i-1][j]。这个动归的复杂度是O(26n),符合要求。实际上空间上可以只开一个26大小的数组,每次只更新s[i]对应字符位置的dp。
代码如下:
第三题:
题意:n个学生(n<=10000)m个(m<=100)地方。每个学生i有一个唯一的id,以及到达校门的时间ti。而且他要按顺序去pi个地方办理手续,这个序列用用(oij,wij)表示,也就是第j个地方要去的是oij这个点,而且要呆wij长时间。已知从校门去到每个地方以及地方和地方之间的转移时间都是k。每个地方只能给一个学生办理手续,办理的次序按照先来先服务,如果同时到达id小的优先。问每个学生结束办理手续的时间分别是多少。
思路:对这个题目非常失望,看描述以为是一道图论题,实际上就是模拟,没什么技术含量。把该表示的表示清楚,用队列按照时间顺序挨个处理就好了。给我的一个教训就是,结构体的构造和析构非常耗时,如果不需要这种构造和析构,那么考虑使用指针。
代码如下:
只A了前三道:
第一题:
题意:给出n个数(n≤1000000),可以任意选择两个相邻的数字,如果它们相加的和是奇数,那么可以将这两个数删除。问最后可能剩下的最少的数的数量。
思路:细想可知最后剩下的数的数量是确定的。比如考虑有x个奇数,y个偶数(x>y),那么必然存在某个偶数和奇数相邻可删除。所以数量少的必定最后会全部被删除。最后的答案也就是奇数的数量和偶数数量之差的绝对值咯。
代码如下:
#include <iostream> #include <cmath> using namespace std; int main(){ int n,x,res = 0; scanf("%d",&n); for(int i = 0;i<n;i++){ scanf("%d",&x); res += (x&1); } printf("%d\n",abs((res<<1)-n)); return 0; }
第二题:
题意:给出一个长度为n(n<100000)的只包含小写字符的字符串s[0...n-1],再给出m(m<=200)个字符对(如:ab),表示ab和ba不能出现在串中(后文称这个不能出现的集合为黑名单。问最少删除几个字符能够使得输入串是合法的?
思路:只需求合法的串的最长可能。明显思路是dp。一个显然的一维dp是设dp[x]表示考虑前s[0...x]中,且最后一个字符必须是s[x]的情况下的最长可能。那么dp[x]=max(dp[j]+1),0<=j<=x-1且(s[j],s[x])不出现在黑名单中。两点说明:第一,dp的值不是递增的,所以不能从大到小遍历j,找到第一个(s[j],s[x])不在黑名单中就退出。这一点可以考虑如下例子:acccbd,黑名单是(c,b)。第二:这个dp 的复杂度显然是O(n^2),会超时。
还是考虑上述dp,有没有考虑重复的情况呢?其实是有的,在遍历j的过程中,s[j]处可能出现多个相同的字符的情况,实际上这只需要考虑最长的那个即可。这给出了一个启示:只需要维护以特定字符结尾的最长的数量即可。所以dp设计为:dp(i,j)表示考虑前i的字符的子串且最后一个字符为j(0<=j<=25)的最长可能。那么实际上每遇到一个新的s[i],只需要更新以s[i]为最后一个字符的情况,其他的情况都未变。状态方程为:如果j表示的是s[i]的字符:那么dp[i][j] = max(dp[i-1][k]+1),0<=k<=25且(('a'+k),
s[i])不出现在黑名单中;否则dp[i][j] = dp[i-1][j]。这个动归的复杂度是O(26n),符合要求。实际上空间上可以只开一个26大小的数组,每次只更新s[i]对应字符位置的dp。
代码如下:
#include <iostream> #include <cstring> #include <set> #define N 100005 #define INF 0x3fffffff using namespace std; int n,m; int dp[27]; bool hh[27][27]; int main(){ cin >> n; string s; cin >> s; scanf("%d",&m); for(int i = 0;i<m;i++){ getchar(); char c1,c2; c1 = getchar(); c2 = getchar(); hh[c1-'a'][c2-'a'] = hh[c2-'a'][c1-'a'] = true; } int res = 0; dp[s[0]-'a'] = 1; for(int i = 1;i<n;i++){ int j = s[i]-'a'; if(!hh[j][j])//先更新dp[j],这样后面再更新就不会影响dp[j]了 dp[j]++; else dp[j] = max(dp[j], 1); for(int k = 0;k<26;k++) if(k != j && !hh[k][j]) dp[j] = max(dp[j], dp[k]+1); } for(int i = 0;i<26;i++) res = max(res,dp[i]); cout << n-res << endl; return 0; }
第三题:
题意:n个学生(n<=10000)m个(m<=100)地方。每个学生i有一个唯一的id,以及到达校门的时间ti。而且他要按顺序去pi个地方办理手续,这个序列用用(oij,wij)表示,也就是第j个地方要去的是oij这个点,而且要呆wij长时间。已知从校门去到每个地方以及地方和地方之间的转移时间都是k。每个地方只能给一个学生办理手续,办理的次序按照先来先服务,如果同时到达id小的优先。问每个学生结束办理手续的时间分别是多少。
思路:对这个题目非常失望,看描述以为是一道图论题,实际上就是模拟,没什么技术含量。把该表示的表示清楚,用队列按照时间顺序挨个处理就好了。给我的一个教训就是,结构体的构造和析构非常耗时,如果不需要这种构造和析构,那么考虑使用指针。
代码如下:
#include <cstdio> #include <cstring> #include <string> #include <cstdlib> #include <vector> #include <queue> #include <algorithm> #include <cmath> #include <map> #include <set> #include <iostream> #define N 10005 #define INF 0x3fffffff using namespace std; int n,m,k; struct node{ int now,id; int index; int len; int v; vector<int> s; vector<int> t; node(){ now = id = index = len = v = 0; }; }; node *p ; int res ,beg[105]; struct cmp{ bool operator()(node *a,node *b){ if(a->now == b->now) return a->id > b->id; return a->now>b->now; } }; priority_queue<node*, vector<node*>, cmp> q; int main(){ scanf("%d %d %d",&n,&m,&k); for(int i = 0;i<n;i++){ int num,a,b; p[i] = new node(); scanf("%d %d %d",&p[i]->id,&p[i]->now,&num); p[i]->v = i; p[i]->len = num; for(int j = 0;j<num;j++){ scanf("%d %d",&a,&b); p[i]->s.push_back(a); p[i]->t.push_back(b); } p[i]->index = 0; p[i]->now += k; q.push(p[i]); } while(!q.empty()){ node *tmp = q.top(); q.pop(); int b = max(tmp->now, beg[tmp->s[tmp->index]]); tmp->now = beg[tmp->s[tmp->index]] = b+tmp->t[tmp->index]; if(tmp->index == tmp->len-1){ res[tmp->v] = tmp->now; }else{ tmp->now += k; tmp->index++; q.push(tmp); } } for(int i = 0;i<n;i++) printf("%d\n",res[i]); return 0; }
相关文章推荐
- 2017微软秋季校园招聘在线编程笔试 题目2 Composition
- 2017微软秋季校园招聘在线编程笔试(第一题)
- 2017微软秋季校园招聘在线编程笔试-#1399 : Shortening Sequence
- 2017微软秋季校园招聘在线编程笔试(第三题)
- 2017微软秋季校园招聘在线编程笔试
- 2017微软秋季校园招聘在线编程笔试-#1402 : MS Recognition
- 2017微软秋季校园招聘在线编程笔试-#1401 : Registration Day
- 2017微软秋季校园招聘在线编程笔试 Composition
- 2017微软秋季校园招聘在线编程笔试(第二题)
- 2017微软秋季校园招聘在线编程笔试-#1400 : Composition
- 2017微软秋季校园招聘在线编程笔试 Composition (DP)
- 微软2016校园招聘在线笔试 B Professor Q's Software [ 拓扑图dp ]
- 微软2016校园招聘在线笔试 - 第二题 Professor Q's Software
- 微软2016校园招聘在线笔试第二场 题目1 : Lucky Substrings
- hihocoder: 1239 Fibonacci(微软2016校园招聘9月在线笔试)
- 微软2016校园招聘9月在线笔试C.Fibonacci
- 微软2016校园招聘在线笔试题目-第一题 Magic Box
- 微软2016校园招聘在线笔试第二场 A Lucky Substrings
- 阿里巴巴2016年秋季校园招聘C++研发岗在线笔试附加题第一题
- Lucky Substrings 微软2016校园招聘在线笔试第二场