5道题(18春腾讯)

在这里插入图片描述
法1:我最直接的想法

#include<iostream>
using namespace std;

int main() {
	long long int n, m;
	cin >> n >> m;
	long long int sum = 0;
	int flag = -1;//flag为-1表示为负,为1表示为正
	long long int count = m;
	for (long long int i = 1; i <= n; i++)
	{
		if (count != 0 && flag == -1)
		{
			sum += -i;
			count--;
			if (count == 0)//每次count--后都要判断
			{
				count = m;
				flag = -flag;
			}
		}
		else
		{
			sum += i;
			count--;
			if (count == 0)//每次count--后都要判断
			{
				count = m;
				flag = -flag;
			}
		}
	}
	cout << sum << endl;

	system("pause");
	return 0;
}

后来发现只能通过90%的测试用例,这是由于数据很大的时候会超时。

法2:找规律
首先观察数列,我们可以将一组负正的数出现如(-1,-2,3,4)看做一组,则n个数一共有n / (2m)组,而每一组求和结果为m * m,于是得到前n项和公式为Sn = (n / (2m)) * (m * m) = m * n / 2

int main() {
	long long int n, m;
	cin >> n >> m;
	cout << m*n/2 << endl;

	system("pause");
	return 0;
}

在这里插入图片描述
思路:题中已经说了采用最优策略,那么就是贪心算法,每次牛牛或羊羊都拿剩下牌中最大的即可。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//不过就是贪心,每次每次牛牛或羊羊都拿剩下牌中最大的
bool cmp(int a, int b) { return a > b; }
int main() {
	int n;
	cin >> n;
	vector<int>a(n);
	for (int i = 0; i < n; i++)
		cin >> a[i];
	sort(a.begin(),a.end(),cmp);//降序
	int res = 0;
	int sum1 = 0, sum2 = 0;
	for (int i = 0; i < n; i++)
	{
		if (i % 2==0)
		{
			sum1 += a[i];
		}
		else
		{
			sum2 += a[i];
		}
	}
	cout << sum1 - sum2 << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
思路:
n天共有m块巧克力;
第一天吃的巧克力一定在[1,n]的范围内,那么建立一个数组a,a[i]表示当第一天吃i块巧克力时n天一共要吃至少a[i]块巧克力,显然a数组一定是升序数组。
接下来,只需要二分法查找等于m或小于m的最大值,返回的下标就是最后的结果。

我的第一版代码如下,腾讯说通过了80%的测试用例:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n, m;
int sum(int x) {
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += x;
		x = (x + 1) >> 1;//向上取整
	}
	return sum;
}
int BinarySearch(const vector<int>&a, int low, int high, int target)//二分法查找等于target或小于target的最大值,返回下标
{
	while (low <= high)
	{
		int mid = (low + high) >> 1;
		if (a[mid] == target)
			return mid;
		else if (a[mid] > target)
		{
			high = mid - 1;
		}
		else
		{
			low = mid + 1;
		}
	}
	return high;
}
int main() {
	cin >> n >> m;//n天共有m块巧克力
	vector<int>a(m + 1, 0);//a[i]表示当第一天吃i块巧克力时n天一共要吃至少a[i]块巧克力
	for (int i = 1; i <= m; i++)
	{
		a[i] = sum(i);
	}
	int res = BinarySearch(a, 1, m, m);

	cout << res << endl;
	system("pause");
	return 0;
}

继续进行优化,发现数组a可以其实不用建立,通过了100%的测试用例,代码如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n, m;
int sum(int x) {
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += x;
		x = (x + 1) >> 1;//向上取整
	}
	return sum;
}
int BinarySearch(int low, int high, int target)//二分法查找等于target或小于target的最大值,返回下标
{
	while (low <= high)
	{
		int mid = (low + high) >> 1;
		if (sum(mid) == target)
			return mid;
		else if (sum(mid) > target)
		{
			high = mid - 1;
		}
		else
		{
			low = mid + 1;
		}
	}
	return high;
}
int main() {
	cin >> n >> m;//n天共有m块巧克力
	int res = BinarySearch(1, m, m);

	cout << res << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
动态规划,相当漂亮的一个01背包小变异问题,问题简化为有x+y种物品,其中x种的容积为a,y种的容积为b,背包容积为k,问背包装满一共有多少种解法?根据题意,只需要用到一维数组即可。

还是给出两种写法:一维和二维都实现一下,就当练手哈哈。
二维dp代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;



//dp[i][j]代表前i个物品,当背包大小为j时背包装满一共有dp[i][j]种解法
//dp[i][j]代表前i个物品的容积之和为j的组合数
//初始化dp[i][0]=1;这个很关键


int main() {
	int k, a, x, b, y;
	cin >> k >> a >> x >> b >> y;
	vector<int>v(x + y + 1, 0);
	for (int i = 1; i <= x + y; i++)
	{
		if (i <= x)
			v[i] = a;
		else
			v[i] = b;
	}
	vector<vector<int>>dp(x + y + 1, vector<int>(k + 1, 0));//全部置为0
	for (int i = 0; i <= x + y; i++)
		dp[i][0] = 1;//初始化
	for (int i = 1; i <= x + y; i++)
		for (int j = 0; j <= k; j++)
		{
			if (v[i] <= j)//当前这个物品如果可以装下,那么可装可不装,组合总数为装的总数+不装的总数
			{
				dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - v[i]]) % 1000000007;
			}
			else
				dp[i][j] = (dp[i - 1][j]) % 1000000007;
		}

	cout << dp[x + y][k] << endl;
	system("pause");
	return 0;
}

一维dp代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//dp[j]表示当背包大小为j时背包装满一共有dp[j]种解法
//dp[j] = (dp[j] + dp[j - a])
//dp[j] = (dp[j] + dp[j - b])
//初始化dp[0]=1;这个很关键

int main() {
	int k, a, x, b, y;
	cin >> k >> a >> x >> b >> y;
	vector<int>dp(k + 1, 0);//全部置为0
	dp[0] = 1;
	for (int i = 0; i < x; i++)
		for (int j = k; j - a >= 0; j--)
		{
			dp[j] = (dp[j] + dp[j - a]) % 1000000007;
		}
	for (int i = 0; i < y; i++)
		for (int j = k; j - b >= 0; j--)
		{
			dp[j] = (dp[j] + dp[j - b]) % 1000000007;
		}
	cout << dp[k] << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
在这里插入图片描述
这道题应该算是贪心算法中比较难的题了,程序不是很好写!

思路:显然,时间产生的效益远远大于难度,因此,时间的优先级高于难度;
1.因此,将任务按时间和难度进行降序排序(如果出现时间相同的情况,则再按难度降序排序),将机器按时间和难度(等级)进行降序排序;
2.对于每个任务,选出所有时间上能处理该任务的机器,并在机器等级表machine_grade_count中的等级对应位置+1;(即找出所有满足machine.time >= current_task.time的机器,并在机器等级表count中+1)
3.在所有时间上能处理该任务的机器中选一个既能满足该任务的task_grade,同时又是machine_grade最低的机器;

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
struct node {
	int time, grade;
}machine[maxn], task[maxn];//结构体数组

vector<int>machine_grade_count(105, 0);

int cmp(node a, node b) {
	if (a.time == b.time)
	{
		return a.grade > b.grade;
	}
	return a.time > b.time;//时间优先级更高
}

int main() {
	int numMachine, numTask;
	cin >> numMachine >> numTask;
	for (int i = 0; i < numMachine; i++) {
		cin >> machine[i].time >> machine[i].grade;
	}
	for (int i = 0; i < numTask; i++) {
		cin >> task[i].time >> task[i].grade;
	}
	sort(machine, machine + numMachine, cmp);//降序
	sort(task, task + numTask, cmp);//降序


	int num = 0;
	long long  ans = 0;


	for (int i = 0, j = 0; i < numTask; i++) { //对于每个任务,选出所有时间上能处理该任务的机器,并在机器等级表count中+1;(即找出所有满足machine.time >= current_task.time的机器,并在机器等级表count中+1)
		while (j < numMachine && machine[j].time >= task[i].time)
		{
			machine_grade_count[machine[j].grade]++;
			j++;
		}
		for (int k = task[i].grade; k <= 100; k++)//在所有时间上能处理该任务的机器中选一个既能满足该任务的task_grade,同时又是machine_grade最低的机器
		{
			if (machine_grade_count[k] != 0)
			{
				num++;
				machine_grade_count[k]--;
				ans = ans + 200 * task[i].time + 3 * task[i].grade;
				break;
			}
		}
	}
	cout << num << " " << ans << endl;
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值