国际惯例先放链接洛谷
废话不多说看题~
- 实现代码
#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)(政府给的预期价+x)的情况下,总利润是否大于任意其他预期价下的总利润。
(2)解一系列不等式,算出x的范围(min<= x <=max),并且取绝对值最小的那个输出。如果min > max,则输出"NO SOLUTION"。 - 理解题意后,其实这就是一道数学题了,主要难点在于两点:
(1)根据给出的price和number信息,补全剩下的price和number关系。按照题意,这应该是一个分段函数:小于等于最大price前,相邻price呈线性变化。大于最大price后,以输入的最后一行为斜率递减。
(2)解不等式。要注意当x的系数的正负影响了大于小于的符号。
- 然后是一些细节处理,一开始我开辟了一个trend[][2]数组来存储输入的各price-number对应信息,但是没加入前一行输入的cost和cost_number,这个也会影响number函数的求值,应该加入trend数组里。但是有可能输入的price也包含了cost,这时再加入就重复了,所以先判断一下trend里是否已经有cost了,没有的话就加入,最后排序。
差不多就这些~
- 实现代码
#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;
}
- 后记
- 这个题可以这么想,首先因为最后分摊结束后每一堆的纸牌数量都是一样的,故可以当作每一次都从最左边的牌开始移动,如果最左边的牌数量低于平局数N张,就从它右方的牌挪N张过来,如果高于,就给右方的牌N张,然后最左边的牌就视作分摊完成,这时再把它右边的牌看作第一张牌,如此反复直到最后一张。
- 有个需要预处理的地方,就是输入的数据是每一堆的纸牌数量,我们需要先处理为每一堆纸牌数量与平均数相差的数量,方便后续的移动。
- 实现代码
#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;
}
- 后记
- 预处理:将输入的位置矩阵转变为更方便处理的只含有花生信息的数组存储。一开始我是定义了一个三维的数组存储每个有花生的点的x,y坐标以及value值,后来改成了定义一个struct peanut,直接用结构体标识花生的信息,其实和三维数组差不多,但更简介明了,而且有了点面向对象的意思。
- **这个题不是背包问题或者最短路问题!**题目里有明确说,每一次都是先去摘花生数最多的植株,所以简化了很多。
(然而我相当长的时间都以为这是背包问题(;´д`)ゞ…
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)开头是“-”,和结尾是“-”;
(2)连续两个“-”;
(3)数字-字母; - 还有一个是否开辟数组储存改变过后的字符串的问题,我一开始定义了一个1000长度的数组,但是在洛谷编译的时候最后两个结果都是RuntimeError,就猜想是数组越界了,下载了测试数据一看,果然处理后的字符串长度大概为2500+!这时候直接定义一个数组就不行了,其实根据题意,不需要储存修改后的字符串,每一次处理的时候都直接输出就好啦~
交叉模拟板块的题我就选了这四道来做啦,接下来开启新的单元:排序*(੭ˊᵕˋ)੭ଘ