ACM寒假集训第一次专题任务
一、
题目:Long Loong
解题思路:
因为o出现次数由输入的x所决定,可以想到使用一个循环解决。
AC代码:
#include<iostream>
using namespace std;
int main()
{int X;cin>>X;cout<<"L";for(int i=1;i<=X;i++){cout<<"o";}cout<<"ng";system("pause");return 0;
}
二、
题目:YES or YES?
解题思路:
使用循环将t个字符串全部输入字符串数组并全部转换成小写后与”yes“进行比较。
AC代码:
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main()
{int t;cin>>t;getchar();string s[t+1];for(int i=0;i<t;i++){getline(cin,s[i]);for(int j=0;j<3;j++){s[i][j]=tolower(s[i][j]);}}for(int i=0;i<t;i++){if(s[i]=="yes"){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}}system("pause");return 0;
}
注意:
cin
在读取字符串时,会跳过前导的空白字符(像空格、制表符、换行符),并且在遇到下一个空白字符时停止读取。cin
会把换行符留在输入缓冲区里。这可能会对后续使用 getline
读取输入造成影响。(可在getline
之前用cin.ignore()
清除输入缓冲区里的换行符)
getline
是一个函数,定义于 <string>
头文件中。它会从输入流里读取一行内容,直至遇到换行符为止,并且会把换行符从输入缓冲区中移除。
三、
题目:Even? Odd? G
解题思路:
因为要判断的正整数可能很长,所以用字符串数组接收。通过字符串最后一位数字判断奇偶(查ASCII表可知偶数对应ASCII码也为偶数,可以直接判断)。
AC代码:
#include<string>
using namespace std;
int main()
{int N;cin>>N;cin.ignore();char n[110];string s[110];for(int i=0;i<N;i++){cin>>s[i];n[i]=s[i].back();}for(int i=0;i<N;i++){if(n[i]%2==0){cout<<"even"<<endl;}else{cout<<"odd"<<endl;}}return 0;
}
四、
题目:Problem Generator
解题思路:
t确定几轮测试,每轮测试需要明确比赛轮数m和代表题目的字符串a(n看起来可有可无),遍历a并统计每个难度出现的次数,再判断每个难度次数是否达到要求。统计题目缺少个数并记入数组,测试循环结束后遍历数组输出。
AC代码:
#include<iostream>
#include<string>
#include <algorithm>
using namespace std;
int main()
{int t;cin>>t;int sum[1010]={0};for(int i=0;i<t;i++){int n,m,c[7],T;fill(c,c+7,0);cin>>n>>m;string a;cin>>a;for(auto p=a.begin();p!=a.end();p++){if(*p=='A'){c[0]++;}else if(*p=='B'){c[1]++;}else if(*p=='C'){c[2]++;}else if(*p=='D'){c[3]++;}else if(*p=='E'){c[4]++;}else if(*p=='F'){c[5]++;}else if(*p=='G'){c[6]++;}}for(int j=0;j<7;j++){T=m-c[j];if(T>0){sum[i]+=T;}}}for(int i=0;i<t;i++){cout<<sum[i]<<endl;}return 0;
}
注意:
1、迭代器for(auto p=a.begin();p!=a.end();p++)
。
这种迭代器遍历方式适用于所有提供了 begin()
和 end()
成员函 数的容器,例如 std::vector
、std::list
、std::set
等。
2、std::fill
函数定义于 <algorithm>
头文件中
原型:void fill( ForwardIt first, ForwardIt last, const T& value );
first
:指向要填充元素范围起始位置的迭代器。
last
:指向要填充元素范围结束位置的下一个位置的迭代器。
value
:要赋给指定范围内每个元素的值。
fill(c, c + 7, 0);
的具体分析
c
:在 C++ 里,数组名可以隐式转换为指向数组首元素的指针,所以c
相当于指向数组c
第一个元素的指针,也就是迭代器。c + 7
:指针算术运算,它指向数组c
第 7 个元素之后的位置。0
:要赋给数组元素的值。
五、
题目:rules
解题思路:
直接将题目翻译成编程语言可得
AC代码:
#include<iostream>
using namespace std;
int main()
{int n,m,k,r,SUM=0;cin>>n>>m>>k;for(int i=0;i<m;i++){int sum=0;for(int j=0;j<n;j++){cin>>r;if(r==k){sum++;}}if(sum*2>=n){SUM++;}}if(SUM*2>=m){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}return 0;
}
六、
题目:Many Replacement
解题思路:
(直接翻译题目会超时)使用结构体数组构建映射表,将所有的置换操作按顺序输入;然后从'a'至'z'每一个字母都遍历一次映射表,并将此字母的变换终点[1]输入一个新的字符串fc
[2],此字符串将作为最终的映射表承担对目标字符串S的变换任务。遍历S中的元素,并通过S[i]-'a'
将S中的第i个元素转换成fc
对应下标[3],将fc[S[i]-'a']
输出。
AC代码:
#include<iostream>
#include<string>
using namespace std;
struct replace{char fr;char to;
};
int main()
{int N;string S;int Q;string fc;replace c[200000];cin>>N;cin>>S;cin>>Q;for(int i=0;i<Q;i++){cin>>c[i].fr>>c[i].to;}for(char io='a';io<='z';io++){char o=io;for(int i=0;i<Q;i++){if(o==c[i].fr){o=c[i].to;}}fc[io-'a']=o;}for(int i=0;i<(int)S.size();i++){cout<<fc[S[i]-'a'];}return 0;
}
七、
题目:更好的交换
解题思路:
(直接翻译题目会超时)所以观察示例1:
1 | 2 | 3 | |
---|---|---|---|
1 | 4 | 5 | 6 |
2 | 3 | 2 | 1 |
3 | 9 | 8 | 7 |
经过变换:
1 | 3 | 2 | |
---|---|---|---|
1 | 4 | 6 | 5 |
2 | 3 | 1 | 2 |
3 | 9 | 7 | 8 |
可知,变换不改变这些元素在二维数组中的下标(包括行列)。那么,只需要明确以上表格中加粗部分的最终位置即可确定最终表格。
先在输入数据的同时分别存储初始行列编号,tagx[1100]
与tagy[1100]
分别存储行列编号,下标为正常顺序,储存值为位于当前行(列)的行(列)[4]。再经过m次行(列)变换,直接遍历tagx[]
与tagy[]
即为所求表格。
AC代码:
#include<iostream>
#include <utility>
using namespace std;
int main()
{int n,m,a[1100][1100]={0},tagx[1100],tagy[1100];cin>>n>>m;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>a[i][j];}tagx[i]=tagy[i]=i;}for(int op,x,y,i=1;i<=m;i++){cin>>op>>x>>y;if(op==1){swap(tagx[x],tagx[y]);}else{swap(tagy[x],tagy[y]);}}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(j!=1)cout<<" ";cout<<a[tagx[i]][tagy[j]];}cout<<"\n";}return 0;
}
注意:
std::swap
定义在 <algorithm>
或 <utility>
头文件中,在 C++11 及以后版本中,推荐包含 <utility>
头文件。
它接受两个同类型对象的引用作为参数,然后交换它们的值。
学习总结
语法:
cin
在读取字符串时,会跳过空白字符,并且在遇到下一个空白字符时停止读取,且会把换行符留在输入缓冲区
getline
定义于 <string>
头文件中。它会从输入流里读取一行内容,直至遇到换行符为止,并且会把换行符从输入缓冲区中移除。
以上二者都不包含结束符。
C++语法糖:
一、auto的使用:
1、编译器会根据赋给变量的值自动推导变量类型(必须要赋值)
2、范围for循环for(auto ai : a)
二、Lambda表达式:
基本语法: [capture list] (parameter list) -> return type { function body }
捕获列表(capture list):用于指定 Lambda 表达式可以访问的外部变量。它可以为空,也可以包含一个或多个变量,变量之间用逗号分隔。捕获方式有值捕获和引用捕获两种。
参数列表(parameter list):与普通函数的参数列表类似,用于传递给 Lambda 表达式的参数。可以为空。
返回类型(return type):指定 Lambda 表达式的返回类型。如果 Lambda 表达式的返回类型可以由编译器自动推导得出,这部分可以省略。
函数体(function body):包含 Lambda 表达式要执行的代码。
例如:
#include <iostream>int main() {auto add = [](int a, int b) { return a + b; };int result = add(3, 5);std::cout << "3 + 5 = " << result << std::endl;return 0;
}
中 auto add = [](int a, int b) { return a + b; };
三、时空复杂度:
时间复杂度默认指最大时间复杂度
空间复杂度是衡量程序内存占用的量度,它是变量定义次数的化简结果,采用和时间复杂度完全相同的记号和化简规则。
四、STL
的使用:
1、sort:快速排序,时间复杂度O(nlog(n)),默认用小于号排序,区间左闭右开
2、reverse:翻转元素,时间复杂度O(n),区间左闭右开
3、lower_bound / upper_bound:二分查找,时间复杂度O(log(n))
lower_bound:在有序序列中二分查找「第一个大于等于给定值」的元素,并返回它的迭代器。
upper_bound: 用于查找「第一个大于给定值」的元素,用法与lower_bound相同。
4、常用的STL
容器:pair
stack
queue
priority_queue
vector
deque
list
set
map
string
例如,'a'->'b','b'->'c',且此后不再有针对'c'的变换,即可称'c'为'a'的变换终点。 ↩︎
其中下标0所对应的元素为'a'的变换终点,1为'b'的变换终点,以此类推。 ↩︎
例如,若S[i]'a',则S[i]-'a'0。 ↩︎
例如,tagx[3]==5意味着目前初始表格的第5行在原表格第3行。 ↩︎