声明
题解包含以下内容:
- (相对)高级的 C++ 模板及语法技巧
- 仅适用于 C++20 标准的代码
- 强烈的个人代码风格和 Modern C++ 范式追求
- 泛滥的标准库函数
换句话说就是(相较于其他公开题解)更低的查重率和更高的使用门槛;请酌情使用。
【id:100】【20分】A. 倚天屠龙记(函数模板)
题目描述
江湖中有一个传言,只要倚天剑和屠龙刀中暗藏的秘密拼到一起,就能得到天下无敌的内功秘笈。设计一个函数模板,完成拼凑的功能(将倚天剑的秘密连接到屠龙刀的后面),并将秘笈输出. 其中每个秘密由n个元素组成,类型为T。
输入
第一行输入t表示有t个测试实例
第二行先输入一个大写字母表示数据类型,I表示整数类型,D表示双精度数类型,C表示字符型;然后输入n表示数据个数。
第三行输入倚天剑的n个数据
第四行输入屠龙刀的n个数据
依次输入t个实例
输出
每行输出一个结果
样例
输入样例1 | 输出样例1 |
---|---|
2 I 5 5 3 51 27 9 27 0 0 5 1 C 5 kitty hello | 2700515351279 hellokitty |
Answer
#include<bits/stdc++.h>
using namespace std;
template<typename T>
vector<T> generate_arr( size_t size )
{
vector<T> ret; ret.reserve( size );
for ( size_t i = 0; i < size; ++i ) {
T tmp; cin >> tmp;
ret.push_back( move( tmp ) );
}
return ret;
}
template<typename T>
ostream& operator<<( ostream& os, const vector<T>& arr )
{
for ( auto e : arr ) os << e;
return os;
}
int main()
{
size_t t; cin >> t;
while ( t-- ) {
char type_tag; size_t scale;
cin >> type_tag >> scale;
type_tag = toupper( type_tag );
if ( type_tag == 'I' ) {
auto sword = generate_arr<int>( scale ),
knife = generate_arr<int>( scale );
cout << knife << sword << endl;
} else if ( type_tag == 'C' ) {
auto sword = generate_arr<char>( scale ),
knife = generate_arr<char>( scale );
cout << knife << sword << endl;
} else {
auto sword = generate_arr<double>( scale ),
knife = generate_arr<double>( scale );
cout << knife << sword << endl;
}
}
}
【id:327】【20分】B. OOP 两点间距离(类模板+函数模板)
题目描述
写一个Point类模板,数据成员是两个相同类型的数(int或者double型),分别表示点的X和Y坐标。构造函数和成员函数根据需要添加。
写一个全局函数模板(function template),参数是2个Point类型的对象,函数返回两点之间的距离(浮点数)。
主函数中分别输入两组值,调用函数输出结果。
输入
一共有8个数字。
首先是四个浮点数dx1,dy1,dx2,dy2,分别表示两个浮点型点的坐标
然后是四个整数ix1,iy1,ix2,iy2分别表示两个整型点的坐标
输出
先输出点(dx1,dy1,)到点(dx2,dy2,)的距离,换行。
然后输出点(ix1,iy1)到点(ix2,iy2)的距离,换行。
样例
输入样例1 | 输出样例1 |
---|---|
1.5 3.5 5.5 7.5 3 4 5 6 | 5.65685 2.82843 |
Answer
#include <bits/stdc++.h>
using namespace std;
template<typename T>
requires std::disjunction_v<
std::is_same<T, int>,
std::is_same<T, double>
>
class Point {
T x, y;
public:
Point( T xx, T yy )
: x { xx }, y { yy } {}
Point() : Point( {}, {} ) {}
T get_x() const noexcept { return x; }
T get_y() const noexcept { return y; }
friend istream& operator>>( istream& is, Point<T>& pt )
{
is >> pt.x >> pt.y;
return is;
}
};
template<typename T1, typename T2>
double point_distance( T1&& pt1, T2&& pt2 )
{
return sqrt( (pt1.get_x() - pt2.get_x()) * (pt1.get_x() - pt2.get_x()) +
(pt1.get_y() - pt2.get_y()) * (pt1.get_y() - pt2.get_y()) );
}
int main()
{
Point<double> pt1, pt2;
cin >> pt1 >> pt2;
cout << point_distance( pt1, pt2 ) << endl;
Point<int> pt11, pt22;
cin >> pt11 >> pt22;
cout << point_distance( pt11, pt22 ) << endl;
}
【id:101】【20分】C. 简单类模板(类模板)
题目描述
定义一个列表类,该列表包含属性:数值列表(用长度为100的数组表示),数据长度(实际的数据个数);包含的方法:初始化、插入、删除、打印,方法定义为:
1)初始化,接受外来参数,把数据保存在数值列表中,未使用的列表部分全部初始化为-1
2)插入,接受外来参数的插入位置和插入数值,插入位置从0开始计算,注意从插入位置开始,原有数据都要往后移动一位,且数据长度+1
3)删除,接受外来参数的删除位置,删除位置从0开始计算,注意从删除位置后一位开始,原有数据都要往前移动一位,且数据长度-1
4)打印,把包含的数据按位置顺序输出一行,数据之间单个空格隔开
使用类模板的方法,使得这个类支持整数int类型和浮点数double类型
输入
第一行先输入参数n表示有n个数据,接着输入n个整数
第二行输入两个参数,表示插入位置和插入数值,数值为整数
第三行输入删除位置
第四行先输入参数n表示有n个数据,接着输入n个浮点数
第五行输入两个参数,表示插入位置和插入数值,数值为浮点数
第六行输入删除位置
输出
针对头三行输入,分别执行初始化、插入操作和删除操作,调用打印方法输出列表包含的整数数据
针对接着的三行输入,分别执行初始化、插入操作和删除操作,调用打印方法输出列表包含的浮点数数据
样例
输入样例1 | 输出样例1 |
---|---|
5 11 22 33 44 55 2 888 4 5 1.1 2.2 3.3 4.4 5.5 2 88.8 3 | 11 22 888 33 55 1.1 2.2 88.8 4.4 5.5 |
Answer
#include <bits/stdc++.h>
using namespace std;
template<typename T, typename... Args>
concept AllSame = (same_as<T, Args> && ...);
template<typename T>
requires is_arithmetic_v<T>
class myList {
std::array<T, 100> arr_;
size_t data_length_;
public:
template<AllSame<T> ... Args>
myList( Args&&... args ) {
arr_ = { forward<Args>( args )... };
data_length_ = sizeof...(args);
}
void insert( size_t insert_pos, T value ) {
if ( insert_pos >= 100 )
return;
memcpy( arr_.data() + insert_pos + 1, arr_.data() + insert_pos, sizeof( T ) * (data_length_ - insert_pos) );
arr_[insert_pos] = value;
data_length_++;
}
void erase( size_t erase_pos ) {
if ( erase_pos >= 100 )
return;
memcpy( arr_.data() + erase_pos, arr_.data() + erase_pos + 1, sizeof( T ) * (data_length_ - erase_pos - 1) );
arr_[data_length_ - 1] = -1;
data_length_--;
}
void display() const {
for ( size_t i = 0; i < data_length_; ++i )
cout << arr_[i] << (i < data_length_ - 1 ? " " : "");
cout << endl;
}
void input( size_t scale ) {
for ( size_t i = 0; i < scale; ++i )
cin >> arr_[data_length_++];
}
};
template<typename T>
void foo()
{
size_t n {}; cin >> n;
myList<T> lis; lis.input( n );
size_t insert_pos {}; T insert_val {};
cin >> insert_pos >> insert_val;
lis.insert( insert_pos, insert_val );
size_t erase_pos {}; cin >> erase_pos;
lis.erase( erase_pos );
lis.display();
}
int main()
{
foo<int>();
foo<double>();
}
【id:103】【20分】D. 有界数组模板类(类模板)
题目描述
编写有界数组模板BoundArray(即检查对数组元素下标引用并在下标越界时终止程序的执行),能够存储各种类型的数据。要求实现对数组进行排序的方法sort,及对数组进行查找的方法search。
输入
第一行先输入t,表示有t个测试用例
从第二行开始输入每个测试用例的数据。
首先输入数据类型,I表示int,D表示double,C表示char,接着输入数组的元素个数
然后输入每个元素
最后输入要查找的元素
输出
首先输出从小到大排序的元素
然后输出查找元素的结果,找到则输出下标,没找到则输出-1
样例
输入样例1 | 输出样例1 |
---|---|
2 I 2 1 2 2 D 3 3.5 6.2 2.9 2.1 | 1 2 1 2.9 3.5 6.2 -1 |
Answer
#include <bits/stdc++.h>
using namespace std;
template<typename T>
requires is_arithmetic_v<T>
class BoundArray {
std::vector<T> arr_;
public:
void my_sort() {
std::sort( arr_.begin(), arr_.end() );
}
T search( const T& value ) const {
auto iter = find( arr_.begin(), arr_.end(), value );
return iter == arr_.end() ? -1 : distance( arr_.begin(), iter );
}
T& operator[](size_t pos) {
if ( pos >= arr_.size() )
throw out_of_range( "out of range" );
return arr_[pos];
}
friend istream& operator>>( istream& is, BoundArray<T>& arr ) {
T tmp; is >> tmp;
arr.arr_.push_back( move( tmp ) );
return is;
}
friend ostream& operator<<( ostream& os, const BoundArray<T>& arr ) {
for ( const auto& elem : arr.arr_ )
os << elem << ' ';
return os;
}
};
template<typename T>
void foo( size_t scale )
{
BoundArray<T> arr;
for ( size_t i = 0; i < scale; ++i )
cin >> arr;
arr.my_sort();
cout << arr << endl;
T value {}; cin >> value;
cout << arr.search( value ) << endl;
}
int main()
{
size_t t {}; cin >> t;
while ( t-- ) {
char type_tag {}; cin >> type_tag;
size_t scale {}; cin >> scale;
if ( type_tag == 'I' )
foo<int>( scale );
else if ( type_tag == 'D' )
foo<double>( scale );
else foo<char>( scale );
}
}
【id:102】【20分】E. 矩阵类模板(类模板)
题目描述
设计一个矩阵类模板Matrix,支持任意数据类型的数据。
要求至少包含2个成员函数:矩阵转置函数transport、以及打印输出函数print
编写main函数进行测试,调用类的成员函数完成转置和输出。
输入
第一行先输入t,表示有t个测试用例
从第二行开始输入每个测试用例的数据。
首先输入数据类型,I表示int,D表示double,C表示char,接着输入两个参数m和n,分别表示矩阵的行和列
接下来输入矩阵的元素,一共m行,每行n个数据
输出
输出转置后的矩阵
样例
输入样例1 | 输出样例1 |
---|---|
2 I 2 3 1 2 3 4 5 6 C 3 3 a b c d e f g h i | 1 4 2 5 3 6 a d g b e h c f i |
Answer
#include <bits/stdc++.h>
using namespace std;
template<typename T>
class Matrix {
vector<vector<T>> mat_;
public:
Matrix( vector<vector<T>>&& mat ) : mat_ { move( mat ) } {}
Matrix() = default;
~Matrix() = default;
Matrix& init( size_t m, size_t n ) {
mat_.clear();
for ( size_t i = 0; i < m; ++i ) {
mat_.push_back( {} );
for ( size_t ii = 0; ii < n; ++ii ) {
T tmp {}; cin >> tmp;
mat_[i].push_back( move( tmp ) );
}
}
return *this;
}
Matrix& transport() {
vector<vector<T>> transposed( mat_.front().size(), vector<T>( mat_.size() ) );
for ( size_t i = 0; i < mat_.size(); ++i ) {
for ( size_t ii = 0; ii < mat_.front().size(); ++ii )
transposed[ii][i] = mat_[i][ii];
}
swap( mat_, transposed );
return *this;
}
void print() const {
for ( size_t i = 0; i < mat_.size(); ++i ) {
for ( size_t ii = 0; ii < mat_[i].size(); ++ii )
cout << mat_[i][ii] << (ii < mat_[i].size() - 1 ? " " : "");
cout << endl;
}
}
};
int main()
{
size_t t {}; cin >> t;
while ( t-- ) {
char type_tag {};
size_t m {}, n {};
cin >> type_tag >> m >> n;
if ( type_tag == 'I' )
Matrix<int>().init( m, n ).transport().print();
else if ( type_tag == 'D' )
Matrix<double>().init( m, n ).transport().print();
else Matrix<char>().init( m, n ).transport().print();
}
}