个人纪录——洛谷试炼场,税收+纸牌+花生采摘+字符串的展开,日常四连!【交叉模拟】

国际惯例先放链接洛谷
废话不多说看题~

  • P1023 税收与补贴问题

在这里插入图片描述

  • 实现代码
#include <iostream>
#include <math.h>
#include <stdio.h>
#include<iomanip>
using namespace std;

void change(int& a, int& b)
{
	int t = a;
	a = b;
	b = t;
}//exchange two numbers

int sort(int p[][2], int len)
{
	int flag = 0, max=0;
	for (int i = 0; i < len - 1; i++)
	{
		flag = 0;
		for (int j = 0; j < len - i - 1; j++)
		{
			if (p[j][0] > p[j + 1][0])
			{
				change(p[j][0], p[j + 1][0]);
				change(p[j][1], p[j + 1][1]);
				flag = 1;
			}
		}
		if (flag == 0)
			break;
	}
	return p[len-1][0];//return the maximum number
}

int findnumber(int p[][2], int len,int m)
{
	int p_min=0,number;
	for (int i = 0; i < len; i++)
	{
		if (p[i][0] == m)
			return p[i][1];
		else if (p[i][0] < m)
		{
			p_min = i;
		}
		else
		{
			;
		}
	}
	double k = double((p[p_min+1][1]-p[p_min][1]) / (p[p_min+1][0]-p[p_min][0]));
	number = k * (m - p[p_min][0]) + p[p_min][1];
	return number;
}


int main()
{
	int expected_price, cost, sale_cost, trend[2000][2], descend,flag = 0;//flag: used to mark whether add the cost into trend[][] after inputing.
	cin >> expected_price;
	cin >> cost >> sale_cost;
	int i = 0, max, len;
	do
	{
		cin >> trend[i][0] >> trend[i][1];
		if (trend[i][0] == expected_price)
			flag = 1;//flag = 1: no need to add.
		i++;
	} while (trend[i - 1][0] != -1 || trend[i - 1][1] != -1);
	if (flag == 1)
		len = i;
	else
	{
		trend[i][0] = cost;
		trend[i][1] = sale_cost;
		len = i + 1;
	}
	cin >> descend;
	max = sort(trend, len);
	double price = cost, number, government, gov_plus = 100000, gov_minus = -100000;
	double b = trend[len - 1][1] + descend * max;//calculate the function when price is higher than the maxmimum number.y=kx+b.
	double exp_num;//the sale number according to the expected price.
	if (expected_price < max)
	{
		exp_num = findnumber(trend, len, expected_price);
	}
	else
	{
		exp_num = (-1) * descend * expected_price + b;
	}
	i = 0;
	do
	{
		price += 1;
		if (price < max)
		{
			number = findnumber(trend, len, price);
		}
		else
		{
			number = (-1) * descend * price + b;
		}
		if (number <= 0)
			break;
		//find the number of the price.
		int n = exp_num - number;
		if (n == 0)
			continue;
		else if (n > 0)
		{
			government = ceil(double(price * number - cost * number + cost * exp_num - expected_price * exp_num) / double(exp_num - number));//x>=...
			if (government > gov_minus)gov_minus = government;
		}
		else
		{
			government = floor(double(price * number - cost * number + cost * exp_num - expected_price * exp_num) / double(exp_num - number));//x<=...
			if (government < gov_plus)gov_plus = government;
		}
		//according to the equation, solve the answer.gov_minus<x<gov_plus.
		
	}while (1);
	if (gov_plus < gov_minus)
		cout << "NO SOLUTION";
	else
	{
		int result = gov_plus <= abs(gov_minus) ? gov_plus : gov_minus;
		cout << result;
	}
	return 0;
}
  • 后记:
  1. 理解题意很重要!目的主要是两个:
    (1)(政府给的预期价+x)的情况下,总利润是否大于任意其他预期价下的总利润。
    (2)解一系列不等式,算出x的范围(min<= x <=max),并且取绝对值最小的那个输出。如果min > max,则输出"NO SOLUTION"。
  2. 理解题意后,其实这就是一道数学题了,主要难点在于两点:
    (1)根据给出的price和number信息,补全剩下的price和number关系。按照题意,这应该是一个分段函数:小于等于最大price前,相邻price呈线性变化。大于最大price后,以输入的最后一行为斜率递减。
    在这里插入图片描述
    (2)解不等式。要注意当x的系数的正负影响了大于小于的符号。
    在这里插入图片描述
  3. 然后是一些细节处理,一开始我开辟了一个trend[][2]数组来存储输入的各price-number对应信息,但是没加入前一行输入的cost和cost_number,这个也会影响number函数的求值,应该加入trend数组里。但是有可能输入的price也包含了cost,这时再加入就重复了,所以先判断一下trend里是否已经有cost了,没有的话就加入,最后排序。

差不多就这些~

  • P1031 均分纸牌

在这里插入图片描述

  • 实现代码
#include <iostream>
#include <math.h>
#include <stdio.h>
#include<iomanip>
using namespace std;

int main()
{
	int n, cards[100],total=0,average,count=0;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> cards[i];
		total += cards[i];
	}
	average = total / n;
	for (int i = 0; i < n; i++)
	{
		cards[i] = cards[i] - average;
	}
	for (int i = 0; i < n; i++)
	{
		if (cards[i] == 0)
			continue;
		else
		{
			cards[i + 1] += cards[i];
			count++;
		}
	}
	cout << count;
	return 0;
}
  • 后记
  1. 这个题可以这么想,首先因为最后分摊结束后每一堆的纸牌数量都是一样的,故可以当作每一次都从最左边的牌开始移动,如果最左边的牌数量低于平局数N张,就从它右方的牌挪N张过来,如果高于,就给右方的牌N张,然后最左边的牌就视作分摊完成,这时再把它右边的牌看作第一张牌,如此反复直到最后一张。
  2. 有个需要预处理的地方,就是输入的数据是每一堆的纸牌数量,我们需要先处理为每一堆纸牌数量与平均数相差的数量,方便后续的移动。
  • P1086 花生采摘

在这里插入图片描述
在这里插入图片描述

  • 实现代码
#include <iostream>
#include <math.h>
#include <stdio.h>
#include<iomanip>
using namespace std;

struct peanuts 
{
	int x;
	int y;
	int value;
};

void sort(peanuts peanut[], int count)
{
	int flag;
	for (int i = 0; i < count - 1; i++)
	{
		flag = 0;
		for (int j = 0; j < count - i - 1; j++)
		{
			if (peanut[j].value < peanut[j + 1].value) { peanuts t = peanut[j]; peanut[j] = peanut[j + 1]; peanut[j + 1] = t; flag = 1; }
		}
		if (flag == 0)
			return;
	}
}

int main()
{
	peanuts peanuts[2000];
	int M, N, K, value,count=0;
	cin >> M >> N >> K;
	for (int i = 0; i < M; i++)
	{
		for (int j = 0; j < N; j++)
		{
			cin >> value;
			if (value == 0)
			{
				continue;
			}
			else
			{
				peanuts[count].value = value;
				peanuts[count].x = i + 1;
				peanuts[count].y = j + 1;
				count++;
			}
		}
	}
	sort(peanuts, count);
	int values = 0, time=K, per_time;
	for (int i = 0; i < count; i++)
	{
		if (i == 0)
		{
			if ((peanuts[i].x * 2 + 1) >= K)
				break;
			time = K - peanuts[i].x -1;
		}
		else
		{
			per_time = abs(peanuts[i].x - peanuts[i-1].x) + abs(peanuts[i].y - peanuts[i-1].y) +1; // time = (x2-x1)+(y2-y1)
			time -= per_time;
		}
		if ((time-peanuts[i].x) < 0)
		{
			break;
		}
		else
		{
			values += peanuts[i].value;
		}
	}
	cout << values;
	return 0;
}
  • 后记
  1. 预处理:将输入的位置矩阵转变为更方便处理的只含有花生信息的数组存储。一开始我是定义了一个三维的数组存储每个有花生的点的x,y坐标以及value值,后来改成了定义一个struct peanut,直接用结构体标识花生的信息,其实和三维数组差不多,但更简介明了,而且有了点面向对象的意思。
  2. **这个题不是背包问题或者最短路问题!**题目里有明确说,每一次都是先去摘花生数最多的植株,所以简化了很多。(然而我相当长的时间都以为这是背包问题(;´д`)ゞ…

P1098 字符串的展开

在这里插入图片描述

  • 代码实现
#include <iostream>
#include <math.h>
#include <stdio.h>
#include<iomanip>
#include<cstring>
using namespace std;

int fun(char pre_nums[],char a,char b, int p1, int p2, int p3)
{
	int count = 0, middle = 0,total_middle=0,flag;//flag = 0, number;flag = 1, letter;
	char* head;
	if (b - a == 1)
	{
		return -1;
	}
	else if (b - a <= 0)
	{
		return -2;
	}
	else
	{
		//judge whether the variable is letter or number.
		if (a >= 'A' && a <= 'Z')
		{
			a = a - 'A' + 'a';
			flag = 1;
		} //先统一a为小写
		else if (a >= 'a' && a <= 'z')
		{
			flag = 1;
		}
		else
		{
			flag = 0;
		}
		
		middle = b - a -1;
		total_middle = p2 * middle;
		head = (char*)malloc(total_middle+1);
		for (int i = 0; i < total_middle+1; i++)
			head[i] = '\0';
		char* after_nums = head;
		for (int i = 1; i <= middle; i++)
		{
			for (int j = 1; j <= p2; j++)
			{
				if (p1 == 3)
				{
					*after_nums = '*';
					after_nums++;
				}
				else if(p1==1)
				{
					*after_nums = a + i;
					after_nums++;
				}
				else
				{
					if (flag == 1)
					{
						*after_nums = a - 'a' + 'A' + i;
						after_nums++;
					}
					else
					{
						*after_nums = a + i;
						after_nums++;
					}
				}
			}
		}
		if (p3 == 1)
		{
			cout << head;
		}
		else
		{
			char* inv_nums;
			inv_nums = (char*)malloc(total_middle+1);
			for (int i = 0; i < total_middle+1; i++)
				inv_nums[i] = '\0';
			char* inv_nums_after = inv_nums;
			int i = 0, j = total_middle-1;
			while (j>=0)
			{
				inv_nums[i] = head[j];
				i++;
				j--;
			}
			cout << inv_nums;
		}
		return total_middle;
	}
}

int main()
{
	int p1, p2, p3;
	char ori_nums[150],pre_nums[100];
	cin >> p1 >> p2 >> p3;
	cin >> ori_nums;
	char* point = ori_nums;
	int len = strlen(ori_nums),pre=0,middle=0;
	
	for (int i = 0; i < len; i++)
	{
		if (ori_nums[i] != '-')
		{
			cout << ori_nums[i];
		}
		else
		{
			if ((i == 0) || (ori_nums[i + 1] == '-' || ori_nums[i - 1] == '-') || (i == len - 1) || ((ori_nums[i - 1] >= '0' && ori_nums[i - 1] <= '9' && ori_nums[i + 1] >= 'a' && ori_nums[i + 1] <= 'z') || (ori_nums[i + 1] >= '0' && ori_nums[i + 1] <= '9' && ori_nums[i - 1] >= 'a' && ori_nums[i - 1] <= 'z')))cout << ori_nums[i];
			else
			{
				middle = fun(pre_nums, ori_nums[i - 1], ori_nums[i + 1], p1, p2, p3);
				if (middle == -1)
				{
					continue;
				}
				else if (middle == -2)
				{
					cout << '-';
				}
				else
					;
			}
		}
	}
	return 0;
}
  • 后记
  1. 这个题我觉得最考验的就是处理边界问题!主要有以下几个边界问题需要处理:
    (1)开头是“-”,和结尾是“-”;
    (2)连续两个“-”;
    (3)数字-字母;
  2. 还有一个是否开辟数组储存改变过后的字符串的问题,我一开始定义了一个1000长度的数组,但是在洛谷编译的时候最后两个结果都是RuntimeError,就猜想是数组越界了,下载了测试数据一看,果然处理后的字符串长度大概为2500+!这时候直接定义一个数组就不行了,其实根据题意,不需要储存修改后的字符串,每一次处理的时候都直接输出就好啦~

交叉模拟板块的题我就选了这四道来做啦,接下来开启新的单元:排序*(੭ˊᵕˋ)੭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值