微软2016校招笔试 第二场部分题目个人思路
2015-04-25 20:10
344 查看
A. Lucky Substrings
这道题并不难,由于字符串长度只有100,那么它的子串肯定不超过1w个,枚举出所有字串都是没有问题的,至于检验一个子串里面不同的字母数量是不是斐波那契数,我们只需要事先把斐波那契数列小于26的项都生成出来(最多每个字母都出现一遍,就是26嘛),然后枚举一个子串之后,统计出不同字母的数量(边找边统计,如果当前字母之前出现过就不加,如果没出现过就记住并+1),去这个里面找就行了。斐波那契数列推不了几项就到26了……最后要字典序从小到大排列,并且还要去重,那就用string然后直接sort+unique一发,搞定
#include<iostream> #include<stdio.h> #include<math.h> #include<string.h> #include<string> #include<algorithm> using namespace std; char s[200]; string ans[20000]; int p_ans=0; int fib[10000]; int p_fib=0; void gener_fb() { fib[1]=1; fib[2]=1; int i=3; while(true) { fib[i] = fib[i-1]+fib[i-2]; if(fib[i]>26) { p_fib =i; return; } i++; } } bool find(int x) { for(int i=1; i<=p_fib;i++) { if(fib[i] == x) return true; } return false; } int main() { gener_fb(); cin>>s; int len=strlen(s); int i; for(i=0;i<len;i++) { char now[200]={0}; int appear[200]={0}; int sum_appear=0; for(int j=i; j<len; j++) { now[j-i] = s[j]; if(appear[s[j]]==0) { appear[s[j]]=1; sum_appear ++; } if(find(sum_appear)) { string str(now); ans[++p_ans] = str; } } } sort(&ans[1], &ans[p_ans+1]); p_ans = unique(&ans[1], &ans[p_ans+1]) - ans-1; for(i=1;i<=p_ans;i++) { cout<<ans[i]<<endl; } //system("pause"); return 0; }
B. Numeric Keypad
这道题我还是想了一会的,我也不知道其他人是怎么做的……这道题可以注意到这么几点,首先就是输入的数特别大,有500位,所以我们肯定是要一位一位处理,每一位都要尽量和输入的一样,因为如果前面有一位小了,后面再大也没用;
关键问题是有的时候如果你输的一样的话,后面就不行了,比如样例的131,你如果第二位输了3,那你会发现第三位无解了。怎么办呢?其实很容易,这个时候我们只需要回退到上一层并尝试一个更小的数字即可。你会发现这样的回退最多只会出现一次,因为一旦回退之后,后面的你都可以无脑的填了。如果回退的那一位不是0的话,那么你后面可以无脑填9,比如131你回退到12的时候,后面你都不用想了,肯定全填9,反正你在第二位已经比他小了;如果回退这一位是0的话就不行了,因为0到不了9,就只能后面全无脑填0了,比如876这个例子答案就是800.
建议预先处理一个
map[i][j],表示数字i能不能到数字j去,这样会给你后面省很多事。
#include<iostream> #include<string.h> #include<math.h> #include<stdio.h> #include<algorithm> using namespace std; char input[600]; int t; int map[10][10]; int ans[600]; void initmap() { int i,j; for(i=1;i<=9;i++) { for(j=1;j<=9;j++) { if( (i-1)/3 <= (j-1)/3 && (i-1)%3 <=(j-1)%3) map[i][j]=1; } } for(i=1;i<=7;i+=3) map[i][0]=1; for(i=2;i<=8;i+=3) map[i][0]=1; map[0][0]=1; return; } bool go(int pos, int last) { if(pos==strlen(input)) return true; int now = input[pos]-'0'; bool ok=false; for(int i=now; i>=0; i--) { if(map[last][i]==1) { ans[pos]=i; if(i==now) { if(go(pos+1, i) == false) { continue; } else return true; } else { for(int tmp=pos+1; tmp<strlen(input); tmp++) { if(i==0) ans[tmp]=0; else ans[tmp]=9; } return true; } } } return false; } void init() { memset(ans,0,sizeof(ans)); } int main() { initmap(); cin>>t; for(int files=1; files<=t; files++) { init(); cin>>input; go(0,1); for(int i=0; i<strlen(input);i++) cout<<ans[i]; cout<<endl; } //system("pause"); return 0; }
C. Spring Outing
这题当时我的算法WA了,然后想了半天也没想出来哪儿错,后来今天讨论才知道的……这道题目的关键就在于“已经知道的肯定可以去的地方”,一开始大家都知道“我至少可以待在家里”。
那么考虑这么一个事情,对于某一个人来说,如果前面所有的地点都被pass掉了,现在投K的话,如果K在0后面,那我肯定不投;如果K在0前面,那我肯定就要投,不然没别的选择我就得在家呆着了;这样,我们根据所有人的行为就能知道K到底能不能去,如果有一半人都会投K的话,那么K就可以去了,反之K就不能去;
同样的道理,如果K可以去了,我们看K-1的时候,如果某个人更想去K-1,那他一定会投的,否则一定不会投的。当然如果刚才结果是K去不了,那么现在最后一个肯定能去的选择就是0,就变成了K-1和0之间的选择。
所以,我们只需要从第K号地点往前试,试完K个就知道他们会在哪个地点达到第一次(也就是我们这个算法当中的最后一次)过半数了。
由于输入都是0~n的排列,所以我们可以将每个数在每个人当中的位置记录下来,这样找起来就非常方便了。
注意,并不是说一个人绝对不会投一个已知可取的地方的后面的票的,比如一个人的志愿是0 1 2,那么根据刚才的结论,如果2已经可以去了,他还是会投1的,要不然就铁定去2了。并不是说一个人想在家呆着就一定会一直憋着。
本题由于还没有开放,所以就不贴代码了。
相关文章推荐
- 微软2016校招笔试 第一场部分题目个人思路
- 题目3 : Spring Outing 微软2016校园招聘在线笔试第二场
- 2016 微软秋招(校招)在线笔试 题目1 : Farthest Point
- 2016 微软秋招(校招)在线笔试 题目234
- 微软2016校园招聘在线笔试第二场 题目1 : Lucky Substrings
- 2016腾讯校招笔试 (部分题目)
- 微软2016校园招聘在线笔试第二场 题目1 : Lucky Substrings
- 【hihocoder】1237 : Farthest Point 微软2016校招在线笔试题
- 中兴2016年校招笔试题目(部分)(二)
- (2016)京东笔试校招编程题目
- 微软苏州校招笔试题目(1月10日)Colorful Lecture Note的解法
- 微软2016校园招聘在线笔试第二场——Lucky Substrings
- Spring Outing 微软2016校园招聘在线笔试第二场
- 2014.3.29 阿里巴巴 实习校招 笔试 题目及部分参考答案
- 微软2016校园招聘在线笔试第二场
- 微软2016校园招聘4月在线笔试题目解析
- 2014.3.29 阿里巴巴 实习校招 笔试 题目及部分参考答案
- Lucky Substrings 微软2016校园招聘在线笔试第二场
- 微软2016校招笔试题
- 微软2016校招--题目2 : 403 Forbidden ----还是错误的,自己留念,不误导大家