第一次双周赛
第一题
题目1
n个网格的土壤土地排成一行,从1到n,其中一些是百合花。在网格上放一些猫粮,但对于任何有猫粮的网格i,在区域[i−1, i+1]不得含有百合花。最大限度地增加有猫粮的格子。
思路1
有猫粮的格子最多时,第一个土壤必须放猫粮。接着逐个先后移动,若能放猫粮就放猫粮,直到结束。此时则为答案。
代码1
#include<iostream>
using namespace std;
//存放是否有百合花
bool grid[1001];
int n;
int main()
{
//输入
cin >> n;
for (int i = 1; i <= n; i++)
{
char g;
cin >> g;
if (g == 'L')
{
grid[i] = true;
}
else
{
grid[i] = false;
}
}
//边缘两个网格设置为无百合花,便于遍历
grid[0] = grid[n + 1] = false;
//答案
string ans = "";
for (int i = 1; i <= n; i++)
{
//保证附近无百合
if (!grid[i - 1] && !grid[i] && !grid[i + 1])
{
ans += "C";
}
//该网格是百合
else if (grid[i])
{
ans += "L";
}
//该网格附近有百合
else
{
ans += ".";
}
}
cout << ans << endl;
return 0;
}
第二题
题目2
求16进制数的高精乘法
思路2
与10进制的高精度乘法类似,只需要把进位时的10改为16,再添加16进制与10进制转换,即可实现
代码2
#include<iostream>
using namespace std;
//最大可能的位数
const int Max = 10000;
//第一个高精数,第二个高精数,结果高精数
int high1[Max], high2[Max], result[Max];
//第一个高精数长度,第二个高精数长度,结果高精数长度
int length1, length2, lengthr;
//相乘函数
void multiply()
{
//直接相乘
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
result[i + j] += high1[i] * high2[j];
}
}
//进位
for (int i = 0; i < Max - 1; i++)
{
result[i + 1] += result[i] / 16;
result[i] %= 16;
}
//计算位数
for (int i = Max - 1; i >= 0; i--)
{
if (result[i] != 0)
{
lengthr = i + 1;
return;
}
}
}
//将16进制数字字符串逐字符转换为10进制(以数组形式)
void HexToDec(string hex, int* high)
{
for (int i = hex.size() - 1; i >= 0; i--)
{
if (hex[i] >= '0' && hex[i] <= '9')
{
high[hex.size() - 1 - i] = hex[i] - '0';
}
else if (hex[i] >= 'A' && hex[i] <= 'F')
{
high[hex.size() - 1 - i] = hex[i] - 'A' + 10;
}
}
}
//将结果数组转换为16进制数字字符串
string DecToHex()
{
string s = "";
for (int i = lengthr - 1; i >= 0; i--)
{
if (result[i] >= 0 && result[i] <= 9)
{
s += result[i] + '0';
}
else if (result[i] >= 10 && result[i] <= 15)
{
s += result[i] - 10 + 'A';
}
}
return s;
}
int main()
{
//输入和转换
string input;
cin >> input;
HexToDec(input, high1);
length1 = input.size();
cin >> input;
HexToDec(input, high2);
length2 = input.size();
//线程
multiply();
//输出
if(lengthr == 0)
{
cout << 0 << endl;
return 0;
}
cout << DecToHex() << endl;
return 0;
}
第三题
题目3
有n个敌人在某处以1m/s速度接近,小明有射程为m的枪,且枪需要换弹,问小明最长的换弹时间。
思路3
该题叫容易判断答案是否正确,并且答案的范围极大,可以使用二分答案。
判断答案是否正确的思路:模拟时间的推进,若有敌人到达了小明则不正确。
代码3
#include<cstdio>
#include<algorithm>
using namespace std;
int enemy[100000];
int n, m;
//快读(不需要)
inline void read(int &x)
{
int s = 0, w = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
x = s*w;
}
//判断函数
bool check(int speed)
{
//过去的时间
int time = 0;
//如果最近的敌人还在射程外,则快进时间到敌人进入射程
time += max(0, enemy[0] - m);
//循环模拟时间流逝(以一个个敌人为单位,一次循环处理一个敌人)
for (int i = 1; i < n; i++)
{
//换弹时间
time += speed;
//如果敌人已经到了,就是无效答案
if (enemy[i] < time)
{
return false;
}
//如果敌人在射程外,快进时间到敌人进入射程
time += max(0, enemy[i] - time - m);
}
//如果处理完了,就说明答案有效
return true;
}
int main()
{
//读取
read(n);
read(m);
for (int i = 0; i < n; i++)
{
read(enemy[i]);
}
//排序,保证近的敌人在前,方便检查
sort(enemy, enemy + n);
//左边界、有边界、答案
int l = 1, r = enemy[n - 1] / n, ans;
//二分
while (l <= r)
{
//中间值
int mid = (l + r) / 2;
//判断,若有效则更新答案,并继续判断右边界
if (check(mid))
{
ans = mid;
l = mid + 1;
}
//无效则在左边界判断
else
{
r = mid - 1;
}
}
printf("%d", ans);
return 0;
}
第四题
题目4
给一个链表,和一个数k,要求逐k个将链表的节点反转
思路4
写一个结构体,存储数据和下一个节点。用一个数组存链表(索引为地址)。再用一个新数组存反转后的链表,计算得到下一个节点的地址。最后再逐个输出新数组。
代码4
#include<iostream>
#include<cstdio>
using namespace std;
//节点结构体
struct node
{
int next;
int item;
};
//原链表
node list[100005];
//由链表头开始先后遍历的索引得到地址
int indexToAddress[100005];
//新链表
node newlist[100005];
int main()
{
//首地址
int firstAddress;
//临时存储地址,n,k,临时存储数据,临时存储下一个地址
int address, n, k, item, next;
cin >> firstAddress >> n >> k;
//建立链表
for (int i = 1; i <= n; i++)
{
cin >> address >> item >> next;
node n;
n.item = item;
n.next = next;
list[address] = n;
}
//从链表头开始遍历整个链表,以获得真正的链表中节点的个数,处理有给出的节点不在链表上的情况
address = firstAddress;
n = 0;
int i = 1;
while (address != -1)
{
indexToAddress[i] = address;
address = list[address].next;
i++;
n++;
}
//需要反转的次数
int reverse = n / k;
//第k次反转的首节点地址
firstAddress = indexToAddress[k];
//反转
for (int i = 0; i < reverse; i++)
{
//除该次反转的首节点(首节点的下一个节点在下一次反转的节点中,单独处理)
for (int j = 0; j < k - 1; j++)
{
//当前节点在反转后对应的序号
int index = i * k + k - j;
//新节点
node newNode;
newNode.item = list[indexToAddress[index]].item;
//当前节点在反转后的下一个节点是反转前前一个节点
newNode.next = indexToAddress[index - 1];
//添加至新链表
newlist[indexToAddress[index]] = newNode;
}
//处理该次反转的首节点
node newNode;
newNode.item = list[indexToAddress[i * k + 1]].item;
//如果还有下一次反转,则该次反转后的这一段的末节点是下一次反转在反转前的末节点
if (i * k + 2 * k <= n)
{
newNode.next = indexToAddress[i * k + 2 * k];
}
//否则就是反转前末节点的下一个节点
else
{
newNode.next = list[indexToAddress[i * k + k]].next;
}
//添加至新链表
newlist[indexToAddress[i * k + 1]] = newNode;
}
//不需要反转的部分
for (int i = reverse * k + 1; i < n + 1; i++)
{
newlist[indexToAddress[i]] = list[indexToAddress[i]];
}
//遍历输出
address = firstAddress;
while (address != -1)
{
if (newlist[address].next == -1)
{
printf("%05d %d %d\n", address, newlist[address].item, newlist[address].next);
}
else
{
printf("%05d %d %05d\n", address, newlist[address].item, newlist[address].next);
}
address = newlist[address].next;
}
return 0;
}
第五题
题目5
求一个一元三次方程在一定范围内的解
思路5
设该一元三次方程的导函数的零点为a, b,该一元三次方程的三个根分别在(-∞, a),(a, b),(b, +∞)之间。则可以先求导函数的零点,在分三块分别二分查找零点位置。
代码5
#include<iostream>
#include<iomanip>
using namespace std;
//导函数两个零点(两个极值)
double m1, m2;
//给定系数
double a, b, c, d;
//给定范围
double p, q;
//导函数
double fd(double x)
{
return 3 * a * x * x + 2 * b * x + c;
}
//原函数
double f(double x)
{
return a * x * x * x + b * x * x + c * x + d;
}
//求零点(二分)(参数:函数,左边界,右边界)
double getZeroPoint(double (* f)(double), double l, double r)
{
//二分
while (l <= r)
{
//中间值
double mid = (l + r) / 2;
//求函数值
double y = f(mid);
//精度要求为1e-6,所以范围要小于1e-6
if (-1e-8 < y && y < 1e-8)
{
return mid;
}
//零点在左侧
else if (y * f(l) <= 0)
{
r = mid;
}
//零点在右侧
else
{
l = mid;
}
}
}
//求极值(导函数的零点)
void getMaxAndMin()
{
double mid = - (2 * b) / (3 * a) /2;
m1 = getZeroPoint(&fd, p, mid);
m2 = getZeroPoint(&fd, mid, q);
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a >> b >> c >> d >> p >> q;
getMaxAndMin();
cout << setiosflags(ios::fixed) << setprecision(6) << getZeroPoint(&f, p, m1) << " " << getZeroPoint(&f, m1 ,m2) << " " << getZeroPoint(&f, m2, q) << " " << endl;
}
return 0;
}