编程笔记三

前言

网易游戏(互娱)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(mn)
    题解代码:
#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. 分别从低到高重新排列基站的海拔和洪水的海拔高度;
  2. 依次判断每次洪水淹没的基站,沉下去的基站有三种状态:(1)左右已沉,总集群数-1;(2)单边沉,总集群数不变;(3)左右均没沉,总集群数+1。
    时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
#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(tT)
#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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值