前言
网易游戏(互娱)2020校招在线笔试-游戏研发第一批(牛客网的题)
1.二进制计数-研发
题目:
小A刚学了二进制,他十分激动。为了确定他的确掌握了二进制,你给他出了这样一道题目:给定N个非负整数,将这N个数字按照二进制下1的个数分类,二进制下1的个数相同的数字属于同一类。求最后一共有几类数字?
输入描述:
输入的第一行是一个正整数T(0<T<=10),表示样例个数。
对于每一个样例,第一行是一个正整数N(0<N<=100),表示有多少个数字。
接下来一行是N个由空格分隔的非负整数,大小不超过2^31-1。
1
5
8 3 5 7 2
输出描述:
对于每一组样例,输出一个正整数,表示输入的数字一共有几类。
3
条件限制:
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 64M,其他语言128M
解法思路:
- 二进制下1的个数统计三种方式:右移位,左移位和与运算。
int one_count(int x)
{
int count = 0;
/*方法1:
思想:x>>,最低位与1做&(1的位不动,x位右移)
右移操作符(>>),正数高位补0,负数高位补1
计算机操作均是用补码进行运算的,正数补码和原码相同,负数补码的补码=源码
因此该方法在处理负数时会造成死循环,比如-1的补码(8位)1111 1111 右移位以后仍为1111 1111
修改方法:取绝对值
*/
if (x < 0)
{
count++;
x = abs(x);
}
while (x)
{
if (x & 1)
{
count++;
}
x = x >> 1;
}
/*方法2:
左移操作符(<<),最低位补0
思想:<< 无符号的1,与x做&(x位不动,无符号的1左移),由于负数存储为补码,因此-1求出为32与
部分题目二进制原码所需的2位不相符,因此可以通过取绝对值
*/
while (x)
{
if (x & 1)
{
count++;
}
x = x << 1;
}
/*方法3:(最优方法)
x = x & (x-1)
思想:循环只需要x中1的次数,
*/
while (x)
{
count++;
x = x & (x - 1);
}
return count;
}
- 题解代码:
#include <iostream>
#include <vector>
using namespace std;
int one_count(int x)
{
int count = 0;
while (x)
{
count++;
x = x & (x - 1);
}
return count;
}
int main()
{
int t, n;
int oneCount[33] = { 0 };
cin >> t;
while (t--)
{
int oneIndx, tmp, sum = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> tmp;
oneIndx = one_count(tmp);
if (oneCount[oneIndx] == 0)
{
sum++;
oneCount[oneIndx]++;
}
}
cout << sum << endl;
}
return 0;
}
运行时间:12ms
占用内存:512k
2.水平线-研发
题目:
伞屉国是一个以太阳能为主要发电手段的国家,因此他们国家中有着非常多的太阳能基站,链接着的基站会组合成一个发电集群。但是不幸的是伞屉国不时会遭遇滔天的洪水,当洪水淹没基站时,基站只能停止发电,同时被迫断开与相邻基站的链接。你作为伞屉国的洪水观察员,有着这样的任务:在洪水到来时,计算出发电集群被洪水淹没后被拆分成了多少个集群。
由于远古的宇宙战争的原因,伞屉文明是一个二维世界里的文明,所以你可以这样理解发电基站的位置与他们的链接关系:给你一个一维数组a,长度为n,表示了n个基站的位置高度信息。数组的第i个元素a[i]表示第i个基站的海拔高度是a[i],而下标相邻的基站才相邻并且建立链接,即x号基站与x-1号基站、x+1号基站相邻。特别的,1号基站仅与2号相邻,而n号基站仅与n-1号基站相邻。当一场海拔高度为y的洪水到来时,海拔高度小于等于y的基站都会被认为需要停止发电,同时断开与相邻基站的链接。
输入描述:
每个输入数据包含一个测试点。
第一行为一个正整数n,表示发电基站的个数 (0 < n <= 200000)
接下来一行有n个空格隔开的数字,表示n个基站的海拔高度,第i个数字a[i]即为第i个基站的海拔高度,对于任意的i(1<=i<=n),有(0 <= a[i] < 2^31-1)
接下来一行有一个正整数q(0 < q <= 200000),表示接下来有q场洪水
接下来一行有q个整数,第j个整数y[j]表示第j场洪水的海拔为y[j],对于任意的j(1<=j<=n),有(-2^31 < y[j] < 2^31-1)
10
6 12 20 14 15 15 7 19 18 13
6
15 23 19 1 17 24
输出描述:
对于每一组样例,输出一个正整数,表示输入的数字一共有几类。
2
0
1
1
2
0
条件限制:
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 64M,其他语言128M
解法思路:
- 暴力求解法(无法满足时间复杂度)
时间复杂度: O ( m ∗ n ) O(m*n) O(m∗n)
题解代码:
#include <iostream>
#include <vector>
using namespace std;
int group(vector<int> arr, int h)
{
int num = 0;
for (int i = 0; i < arr.size(); i++)
{
if (arr[i] > h)
{
num++;
for (int j = i + 1; j < arr.size(); j++)
{
if (arr[j] <= h)
{
i = j;
break;
}
if (j == arr.size() - 1)
num--;
}
}
}
return num;
}
int main()
{
int n, in_data, q,floodHeight;
vector<int> station;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> in_data;
station.push_back(in_data);
}
cin >> q;
for (int i = 0; i < q; i++)
{
cin >> floodHeight;
cout << group(station, floodHeight) << endl;
}
return 0;
}
- 状态解法
- 分别从低到高重新排列基站的海拔和洪水的海拔高度;
- 依次判断每次洪水淹没的基站,沉下去的基站有三种状态:(1)左右已沉,总集群数-1;(2)单边沉,总集群数不变;(3)左右均没沉,总集群数+1。
时间复杂度: O ( m ∗ n ) O(m*n) O(m∗n)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct base {
int h;
int indx;
bool operator <(base tmp)
{
return h < tmp.h;
}
};
int main()
{
int n, q, floodHeight, num = 1;
base inStation;
vector<base> station, flood;
vector<int> groupNum;
vector<int> sinkState;
cin >> n;
sinkState.assign(n + 2, 1);
sinkState[0] = 0;
sinkState[n + 1] = 0;
for (int i = 0; i < n; i++)
{
cin >> inStation.h;
inStation.indx = i + 1;
station.push_back(inStation);
}
sort(station.begin(), station.end());
cin >> q;
groupNum.assign(q, 0);
for (int i = 0; i < q; i++)
{
cin >> inStation.h;
inStation.indx = i;
flood.push_back(inStation);
}
sort(flood.begin(), flood.end());
int travel = 0;
for(auto it = flood.begin(); it != flood.end(); it++)
{
while(travel < n && ((*it).h >= station[travel].h))
{
int flag;
sinkState[station[travel].indx] = 0;
flag = sinkState[station[travel].indx - 1] + sinkState[station[travel].indx + 1];
if (flag == 0)
{
num--;
}
if (flag == 2)
{
num++;
}
travel++;
}
groupNum[(*it).indx] = num;
}
for (auto it = groupNum.begin(); it != groupNum.end(); it++)
{
cout << *it << endl;
}
return 0;
}
3.游泳池-研发
题目:
小明作为一个游泳池管理员,以玩弄给水管和排水管为乐,也因此产生了很多数学题考验小朋友。
现在小明想把这个行动升级,考验一下程序员,做了一个自动装置来控制给水管和排水管。在开始时,给水管和排水管都是打开状态的,并且游泳池里没有水。在自动装置的作用下,每经过t1分钟,给水管的状态都会改变,即从打开状态变为关闭状态或从关闭状态变为打开状态,而同时每经过t2分钟,排水管的状态也会改变。当给水管打开时,给水管每分钟会向游泳池里注入m1升水;当排水管打开时,排水管每分钟会把游泳池里水排走m2升;当给水管和排水管同时打开时,游泳池的水量变化为每分钟(m1-m2)升。当然泳池的水量不能变为负数,同时泳池也有个最大容量m,水量不能超过m升。那么经过t分钟后,游泳池里有多少升水?
输入描述:
输入第一行为一个正整数T,表示有T组数据。
每组数据的为一行包含六个整数,分别表示m, t, m1, t1, m2, t2。
数据范围:
对于所有数据,满足1<=T<=10, 1<=m<=100000, 1<=t<=86400, 1<=m1,m2<=100, 1<=t1,t2<=10。
5
10 2 1 5 2 5
10 2 10 5 2 5
10 2 3 5 2 5
100 100 3 4 4 3
10000 1000 10 5 5 3
输出描述:
对于每一个数据,输出一行,包括一个整数,为在t分钟后游泳池中的水量。
0
10
2
3
2495
条件限制:
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 64M,其他语言128M
解法思路:
- 暴力求解法(遍历每一个时刻)
时间复杂度: O ( t ∗ T ) O(t*T) O(t∗T)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int T,m,t,m1,t1,m2,t2;
cin >> T;
while (T--)
{
cin >> m >> t >> m1;
cin >> t1 >> m2 >> t2;
int flag1 = 0;
int flag2 = 0;
int ans = 0;
for (int i = 0; i < t; i++) {
if (i % t1 == 0)flag1 = flag1 ^ 1;
if (i % t2 == 0)flag2 = flag2 ^ 1;
ans = ans + flag1 * m1 - flag2 * m2;
if (ans < 0)ans = 0;
if (ans > m)ans = m;
}
cout << ans << endl;
}
return 0;
}