网易2017校招编程题
内推挂了,继续再战!
1、分苹果:
小易去买苹果,有两种包装,一种一袋8个,一种一袋6个,小易要买n个苹果(不能多也不能少),输出袋子最少的购买方案下的袋子,若无法正好买到n个,则输出-1。
解:设8个一袋的买了pack8袋,6个一袋的买了pack6袋。想要总袋子数最少,那么肯定优先买8个一袋的,最多能买n/8袋,先另pack8=n/8,计算该情况下,pack6为多少能满足总苹果数为6,若无法满足,则减少pack8的数量,直到可以满足总量为n。
#include<iostream> using namespace std; int main() { int n; cin>>n; int pack8=n/8; int pack6=0; for(pack8;pack8>=0;pack8--) { if((n-8*pack8)%6==0) { cout<<pack8+(n-8*pack8)/6<<endl; return 0; } } cout<<-1<<endl; return 0; }
2、大数的最大奇约数
用f(n)表示n的最大奇约数,输入一个数n,输出f(1)+f(2)+f(3)+...+f(n)。1<=n<=1000000000
解:说一下我的思路以及经过的一些曲折。当然第一个想到的方法就是暴力破解,用一个函数f(n),将n循环除2直到为奇数则返回,但是很明显,本题中n的取值范围很大,这样会超时。
然后想着找规律,首先奇数的最大奇约数就是自己,可以暂时不考虑,最后用等差数列求和公式加进来就可以。对于偶数n来说,每个数都可以表示成2^k*i,其中i为奇数,则i就是它的最大奇约数,我们要做的就是把所有的i加进来。首先,我想到的是存储一下每个偶数ni对应的i,之后只要遍历n,找到对应的i加起来就可以了。既然用偶数n来作为遍历的基准会超时,那考虑从k和i出发。选用了map的数据结构,觉得可以方便查找,然后双层循环,第一层是k,第二层是i,边界条件为2^k*i<=n,将n作为key,i作为value存进map。然后又出现了新问题,map太大,超出内存限制。
然后想到了,为什么要存起来呢,直接加进结果就可以了。设置一个count,来统计已经计算过的偶数数量,作为循环的终止条件。该方法的时间复杂度为O(n/2)。PS:开始只将结果定义为了Long型,发现测试用例只能通过一部分,后来想到中间结果也可能会溢出,都应该定义为long型。
#include <iostream> using namespace std; int main() { long n; cin>>n; long long res=0; long t=2;//用t表示2^k int count=0; while(count<n/2) { for(long i=1;t*i<=n;i=i+2)//找到2^k*i<=n的所有i { res=res+i; count++; } t=t*2; } if(n%2==0) //当n为奇数时,序列中的奇数和 { res=res+n*n/4; } else//当n为偶数时,序列中的奇数和 { res=res+(n+1)*(n+1)/4; } cout<<res<<endl; return 0; }
3、 优雅的点
例如:半径的平方如果为25
优雅的点就有:(+/-3, +/-4), (+/-4, +/-3), (0, +/-5) (+/-5, 0),一共12个点。
#include <iostream> #include <math.h> using namespace std; #define MAXINT 99999 int main() { double n; cin>>n; int res=0; int r=sqrt((double)n); for(int i=0;i<=sqrt(n)+1;i++) { int j=sqrt(n-i*i); if(i*i+j*j==n) { if(i==0||j==0) res=res+2; else res=res+4; } } cout<<res<<endl; return 0; }
4、暗黑的字符串
一个只包含'A'、'B'和'C'的字符串,如果存在某一段长度为3的连续子串中恰好'A'、'B'和'C'各有一个,那么这个字符串就是纯净的,否则这个字符串就是暗黑的。例如:
BAACAACCBAAA 连续子串"CBA"中包含了'A','B','C'各一个,所以是纯净的字符串
AABBCCAABB 不存在一个长度为3的连续子串包含'A','B','C',所以是暗黑的字符串
你的任务就是计算出长度为n的字符串(只包含'A'、'B'和'C'),有多少个是暗黑的字符串。 (1 ≤ n ≤ 30)
解:首先想到递归,若确定了字符串前start-1的排列方式,判断从start起接下来有多少种排列方式。但是该方法时间复杂度过大。于是想到动态规划。
暗黑字符串中,第i位可以为'A','B','C'中的哪些值,取决于i的前两位的排列方式,所有用dp[i][subseq],记录到第i位为止,第i-1、i位的排列为subseq(subseq可以有9中排列)的暗黑字符串的个数,例如,dp[i][AA]表示第i-1位为A且第i位也为A的暗黑字符串的个数。遍历i,依次求出dp[i][]的值,则dp[n-1]维中9个数相加的和则为所求。
#include <iostream> #include <math.h> #include <vector> using namespace std; #define MAXINT 9999999 #define AA 0 #define AB 1 #define AC 2 #define BA 3 #define BB 4 #define BC 5 #define CA 6 #define CB 7 #define CC 8 #define ll long long int main() { int n; while(cin>>n) { if(n==1) { cout<<3<<endl; continue; } if(n==2) { cout<<9<<endl; continue; } ll dp[30][9]; for(int i=0;i<9;i++) dp[1][i]=1; for(int i=2;i<n;i++) { dp[i][AA]=dp[i-1][AA]+dp[i-1][BA]+dp[i-1][CA]; dp[i][AB]=dp[i-1][AA]+dp[i-1][BA]; dp[i][AC]=dp[i-1][AA]+dp[i-1][CA]; dp[i][BA]=dp[i-1][AB]+dp[i-1][BB]; dp[i][BC]=dp[i-1][BB]+dp[i-1][CB]; dp[i][BB]=dp[i-1][AB]+dp[i-1][BB]+dp[i-1][CB]; dp[i][CA]=dp[i-1][AC]+dp[i-1][CC]; dp[i][CB]=dp[i-1][BC]+dp[i-1][CC]; dp[i][CC]=dp[i-1][AC]+dp[i-1][BC]+dp[i-1][CC]; } ll res=0; for(int i=0;i<9;i++) res=res+dp[n-1][i]; cout<<res<<endl; } return 0; }
5、 数字翻转
对于一个整数X,定义操作rev(X)为将X按数位翻转过来,并且去除掉前导0。例如:
如果 X = 123,则rev(X) = 321;
如果 X = 100,则rev(X) = 1.
现在给出整数x和y,要求rev(rev(x) + rev(y))为多少?
#include <iostream> #include <list> using namespace std; int rev(int x) { list<int> tmp; while(x) { tmp.push_back(x%10); x=x/10; } int res=0; while(tmp.front()==0) { tmp.pop_front(); } while(!tmp.empty()) { res=res*10+tmp.front(); tmp.pop_front(); } return res; } int main() { int x,y; cin>>x>>y; x=rev(x); y=rev(y); cout<<rev(x+y)<<endl; return 0; }
6、计算糖果
A,B,C三个人是好朋友,每个人手里都有一些糖果,我们不知道他们每个人手上具体有多少个糖果,但是我们知道以下的信息:
A - B, B - C, A + B, B + C. 这四个数值.每个字母代表每个人所拥有的糖果数.
现在需要通过这四个数值计算出每个人手里有多少个糖果,即A,B,C。这里保证最多只有一组整数A,B,C满足所有题设条件。
输入描述:
输入为一行,一共4个整数,分别为A - B,B - C,A + B,B + C,用空格隔开。
范围均在-30到30之间(闭区间)。
输出描述:
输出为一行,如果存在满足的整数A,B,C则按顺序输出A,B,C,用空格隔开,行末无空格。
如果不存在这样的整数A,B,C,则输出No
解:首先A,B,C的值肯定都大于等于0,且为整数。由于A+B的范围在[0,30],所以直接遍历的时间复杂度并不高。以A为基准进行遍历,当A=a时,则b=(A+B)-a,再判断是否满足a-b=A-B,不满足则改变a的值,继续遍历;若满足,则c=(B+C)-b,判断是否满足b-c=B-C,不满足则改变a的值,继续遍历;满足则跳出,已经确定了A,B,C的值。
#include <iostream> using namespace std; int main() { int AMB,BMC,APB,BPC; cin>>AMB>>BMC>>APB>>BPC; int a=0,b=0,c=0; bool exi=false;//记录是否存在这样的A,B,C for(a=0;a<=APB;a++) { b=APB-a; if(a-b!=AMB) continue; c=BPC-b; if(b-c!=BMC) continue; exi=true; break; } if(exi) cout<<a<<" "<<b<<" "<<c<<endl; else cout<<"No"<<endl; return 0; }