1.蛇形方阵
myCode💻:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int n;
int cnt = 1;
int map[10][10];
int a = 0;
int b = 0;
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
map[i][j] = -1;
}
}
cin>>n;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
map[i][j] = 0;
}
}
map[0][0] = 1;
while (map[a][b+1] == 0 || map[a-1][b] == 0 || map[a][b-1] == 0 || map[a+1][b] == 0){
if (map[a][b+1] == 0){
b++;
map[a][b] = ++cnt;
}
else if (map[a+1][b] == 0){
while (map[a+1][b] == 0){
a++;
map[a][b] = ++cnt;
}
}
else if (map[a][b-1] == 0){
while (map[a][b-1] == 0){
b--;
map[a][b] = ++cnt;
}
}
else if (map[a-1][b] == 0){
while (map[a-1][b] == 0){
a--;
map[a][b] = ++cnt;
}
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout<<setw(3)<<setfill(' ')<<map[i][j];
}
cout<<endl;
}
}
笔记📒:
- 这道题挺有意思的,我把这道题理解为一条蛇在一个地图里面爬行。我在写的时候遇到了两个难点。
- 我的思路是:先建立一个10❌10的二维数组,先把每一个元素都设为-1,在输入n之后,将等下要走的地方全部设为0。由此可以看出-1表示地图外,0表示地图内还没走过的地方。然后写一个while循环遍历这个地图,只要蛇的四周有0就继续爬行。循环里头用if语句来构成优先级,右>下>左>上。if语句里头还有一个while循环,目的是让蛇一直爬到头,否则可能爬着爬着就转弯了。
- 第一个难点在于,一开始定义的数组大小必须要大于9,我一开始看着n<=9就把数组大小设置为9,因为我后面的判断总是比原来的位置大一点,所以一定要预留好位置。
- 第二个难点在于,if语句里必须要写一个while循环从而让蛇一直走到头,否则🐍会拐弯。
- 因为每一个数字占3格,用空格填充,这里还用到了一个知识点:
cout<<setw(3)<<setfill(' ')<<map[i][j];
2.杨辉三角
Code from 洛谷:
#include<cstdio>
int a[21][21];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
a[i][1]=a[i][i]=1;//赋初值
for(int i=1;i<=n;i++)
for(int j=2;j<i;j++)//因为a[i][1]、a[i][i]已经赋值过了,所以循环是2~n-1
a[i][j]=a[i-1][j]+a[i-1][j-1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}
笔记📒:
-
杨辉三角
a[i][j]=a[i-1][j]+a[i-1][j-1]a[i][j]=a[i−1][j]+a[i−1][j−1]
同时这也是组合数的公式,很重要,因为常规组合数公式是阶乘运算会爆,而这个就不怎么会了
赋a[i][1]a[i][1] a[i][i]a[i][i]初值1,接下来就可以递推了
-
在循环之前先设初值:
a[i][1]=a[i][i]=1;//赋初值
3.自动修正
myCode💻:
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
int main() {
char arr[100];
cin>>arr;
for (int i = 0; i < strlen(arr); ++i) {
if (isalpha(arr[i])){
arr[i] = toupper(arr[i]);
}
}
for (int i = 0; i < strlen(arr); ++i) {
cout<<arr[i];
}
}
笔记📒:
- 用到了两个函数:(1)
isalpha()
:判断该字符是不是字母。(2)toupper()
:如果是字母,将其变为大写。 - 我这里的代码其实还可以简略,并不需要判断该字符是否为字母。
- 最短的代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;cin>>s;
for(int i=0;i<s.size();i++)s[i]=toupper(s[i]);
cout<<s;
}
3.凯撒密码
myCode💻:
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
int main() {
int n;
char pwd[100];
int cnt;
cin>>n;
cin>>pwd;
for (int i = 0; i < strlen(pwd); ++i) {
cnt = 0;
while (cnt < n){
if (pwd[i] == 'z'){
pwd[i] = 'a';
}
else pwd[i]++;
cnt++;
}
}
for (int i = 0; i < strlen(pwd); ++i) {
cout<<pwd[i];
}
}
笔记📒:
- 主要的难点在于当字母移到z时又要从a开始,我的解决办法是用while循环,直到移动了n次才停止,期间如果有一个字母达到z就让他回到a。
- 阅读了别人的代码之后发现了一个很好的办法:
putchar((in[j]-'a'+n)%26+'a');
- ta用了取余的办法,有效地解决了越界的问题!
代码如下:
#include <stdio.h>
int main()
{
char in[100];
int n, j;
scanf("%d%s", &n, in); //读入
for(j = 0; in[j] != '\0'; j++)
putchar((in[j]-'a'+n)%26+'a');
//in[j]-'a':读入中对应的第几个字母的位置,比如'a'对应0,'b'对应1,'c'对应2(0开始);
//in[j]-'a'+n:读入中对应字母加上转移位数得到的字母的对应位置。
//比如说'c'这个字母移动3位,就是第2个字母向右移动3个,就是第五个字母,即'f'
//取余26是防止移动位数超过26导致炸掉
//再加上'a',将对应位置还原成字母,再打出来
}
4.口算练习题
Code from Luogu:
#include <iostream> //cin & cout 用iostream
#include <cstring> //memset & strlen 用cstring
#include <cstdio> //sscanf & sprintf 用cstdio
using namespace std;
int main(){
char a;//a用于存储运算符
int n,c,d;//n存储个数不解释,cd存储两个数字
char s[100],b[10];//s存储最终的字符串,b临时变量
cin>>n;
for(int i=0;i<n;i++){
cin>>b;//输入一串字符,有可能是运算符,也有可能是数字
if(b[0]>='a' && b[0]<='z'){
a=b[0];//如果是运算符就存入a,然后输入数字
cin>>c>>d;
}else{
sscanf(b,"%d",&c);//如果是数字就转换b为int存储到第一个数字
cin>>d;//然后输入剩下的第二个数字
}
memset(s,0,sizeof(s));//清空原有的字符串,防止长度判断错误
if(a=='a')//用sprintf格式化
sprintf(s,"%d+%d=%d",c,d,c+d);
else if(a=='b')
sprintf(s,"%d-%d=%d",c,d,c-d);
else if(a=='c')
sprintf(s,"%d*%d=%d",c,d,c*d);
cout<<s<<endl<<strlen(s)<<endl;//输出字符串和字符串长度
}
return 0;
}
笔记📒:
- 这道题一开始难住我的地方在于对于两个或三个的输入情况不知道怎么处理,在阅读了别人的代码之后发现可以先输入第一个,判断是字母还是数字,进而判断输入情况。
- 还有一个难点,就是对于先输入的那个东西要怎么处理。这里用到了sscanf函数,作用是将字符转换为数字。首先将第一个输入为字符,如果发现其为数字,再通过sscanf转换为int就好了。
- sscanf用法:
sscanf(字符变量,"转换成的类型",&转换后赋给的变量)
。 - 最后一个难点在于要将运算式子转换为string类型,这里用到了sprintf函数,作用是发送格式化输出到 str 所指向的字符串。
- sprintf用法:
sprintf(输出到的字符串,"转换的形式",数字变量...)
5.标题统计
myCode
#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
int main() {
char title[100000];
int cnt = 0;
gets(title);
for (int i = 0; i < strlen(title); ++i) {
if (isalpha(title[i]) || isnumber(title[i])){
cnt++;
}
}
cout<<cnt;
}
Note📓:
-
这道题困住我的地方在于不知道怎么处理中间有空格的字符串,我使用了cin和scanf都没有用,后来发现gets可以完美地解决。它的作用是
将一行字符从文件或屏幕中读入,可以读空格,遇到换行跳出。
-
不知道为什么我的代码,在洛谷会编译失败,好像是isnum函数出了点问题。
-
可以用以下代码替代:
if(s[i]>='A'&&s[i]<='Z')
ans++;
if(s[i]>='a'&&s[i]<='z')
ans++;
if(s[i]>='0'&&s[i]<='9')
ans++;
6.文字处理 🌟(重要)
Code from Luogu:
#include<iostream>
#include<cmath>
#include<string>
#include<fstream>
using namespace std;
int n,a;
string qwq;
string c1;
string b1;
int b,c,d=-1,e;//并不全有用
int main()
{
cin>>n;
cin>>qwq;
for(int i=0;i<n;i++)
{
cin>>a;
if(a==1)//操作1
{
cin>>b1;
qwq+=b1;
cout<<qwq<<endl;
}
else if(a==2)//操作2
{
cin>>b>>c;
c1=qwq.substr(b,c);
qwq=c1;
cout<<qwq;
cout<<endl;
}
else if(a==3)//操作3
{
cin>>b>>b1;
qwq.insert(b,b1);
cout<<qwq<<endl;
}
else if(a==4)//操作4
{
cin>>b1;
if(qwq.find(b1)<qwq.size())//找不到会返回一个诡异的数字(反正比字符串长)
cout<<qwq.find(b1)<<endl;
else
cout<<-1<<endl;
}
}
return 0;
}
第二种思路:
#include<cstdio>
#include<cstring>
#define MAXN 101
char s[MAXN],in[MAXN];
int main()
{
int n;
scanf("%d\n%s",&n,s);
for(int i=1;i<=n;i++){
int opt;
scanf("%d",&opt);
if(opt==1){
scanf("%s",in);
strcat(s,in);
printf("%s\n",s);
}else if(opt==2){
int a,b;
scanf("%d %d",&a,&b);
s[a+b]='\0';
strcpy(in,&s[a]);
strcpy(s,in);
printf("%s\n",s);
}else if(opt==3){
int a;
scanf("%d %s",&a,in);
strcat(in,&s[a]);
s[a]='\0';
strcat(s,in);
printf("%s\n",s);
}else{
scanf("%s",in);
char*ans=strstr(s,in);
if(ans!=NULL){
printf("%d\n",int(ans-s));
}else{
printf("%d\n",-1);
}
}
}
return 0;
}
Note:
这题有很多有用的知识,重点掌握!
本题用到的STL:
substr 生成子串,输入位置和长度insert 在字符串中插入字符串
find 查找字符串中某个字符串的位置并返回它的位置
7.honoka的键盘
myCode:
#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
int main() {
int n = 0;
int sum = 0;
int flag = 0;
char arr[100];
cin>>n;
for (int i = 0; i < n; ++i) {
cin>>arr[i];
}
for (int i = 0; i < n - 1; ++i) {
if (arr[i] == 'V'){
if (arr[i + 1] == 'K') sum++;
else if (flag == 0){
arr[i + 1] = 'K';
sum++;
flag = 1;
}
}
if (arr[i] == 'K'){
if (arr[i + 1] == 'K' && flag == 0){
arr[i] = 'V';
sum++;
flag = 1;
}
}
}
cout<<sum;
}
Code from Luogu:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[102];
int main()
{
gets(a);
gets(a);
int ans=0;
for(int i=0;i<strlen(a);i++)
{
if(a[i]=='V' && a[i+1]=='K')
{
ans++;
a[i]='X';
a[i+1]='X';
}
}
for(int i=0;i<strlen(a);i++)
{
if(a[i]!='X' && a[i]==a[i+1])
{
ans++;
break;
}
}
printf("%d",ans);
return 0;
}
笔记📒:
- 我的代码有点问题,有部分测试点不能通过,我大概也知道原因了,我需要先把VK找出来,然后将其标记,接着进行第二次循环,进行修改。
- 洛谷上的这个代码就是这个思路。
这个题无非只有四种排列情况VK KV KK VV
其中,VK是符合要求的,KK和VV都能改一个字符成为VK,只有KV不可以改
先从头到尾跑一遍,把正确的VK都改为X
再跑一遍找到一个KK 或 VV就停
8. 单词覆盖
Code from Luogu:
#include<bits/stdc++.h>//c++万能头文件
using namespace std;//命名空间~
int main() {//主函数
int boy=0,girl=0;//boy和girl用来记下各自的个数
string st;//定义题目给出的字符串
cin>>st;//这个我们校长都能看得懂的输入~
for(int i=0;i<=st.length();i++){//开始发挥计算机的强大功能!
//st.length()为读取字符串长度的函数,c++中最好用string头文件,这里我就直接用万能头文件了~
if (st[i]=='b'||st[i+1]=='o'||st[i+2]=='y')//判断连着的三个字母是否为b、o、y
boy++;//boy计数器加一
if (st[i]=='g'||st[i+1]=='i'||st[i+2]=='r'||st[i+3]=='l')//判断连着的三个字母是否为g、i、r、l
girl++;//girl计数器加一
}
cout<<boy<<endl;//输出boy的个数 换行~
cout<<girl<<endl;//输出girl的个数
return 0;//愉快地结束程序~~~~
}
笔记📒:
- 一开始看到这个题有点懵,看了这个答案发现好巧妙,看来我想复杂了。
9.语句解析
Code from Luogu
#include<cstdio>
using namespace std;
int a[3];char s1,s2;
int main()
{
while (scanf("%c:=%c;",&s1,&s2)==2)//充分利用c++语言优势
a[s1-'a']=s2>='0' && s2<='9' ? s2-'0' : a[s2-'a']; //赋值语句简洁明了
printf("%d %d %d",a[0],a[1],a[2]);
}
Note:
- 我被如何获取字符串里的信息难住了,这个代码的巧妙之处在于用了scanf直接获取了有效数据。
10.赦免战俘
Code from Luogu:
#include<bits/stdc++.h>
using namespace std;
int n,p=1,a[1050][1050];
void di(int x,int l,int q) //x为正方形边长,l、q分别为递归正方形的横纵坐标
{
if(x==2) //递归边界
{
a[l][q]=0;
return;
}
for(int i=l; i<=l+x/2-1; i++)
for(int j=q; j<=q+x/2-1; j++)
a[i][j]=0; //将左上方的正方形清零
di(x/2,l+x/2,q);
di(x/2,l+x/2,q+x/2);
di(x/2,l,q+x/2); //此处是递归剩余的三个正方形
}
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
p*=2; //计算正方形的边长
for(int i=1; i<=p; i++)
for(int j=1; j<=p; j++)
a[i][j]=1; //将a数组先赋值为1
di(p,1,1); //开始递归
for(int i=1; i<=p; i++)
{
for(int j=1; j<=p-1; j++)
cout<<a[i][j]<<" ";
cout<<a[i][p]<<endl; //输出,此处可以避免输出行尾空格
}
return 0;
}
笔记:
- 思路和我的完全一致,但是我被困在不知道函数怎么调用二维数组的指针,还是没有找到解决办法,看了ta的代码后发现其实只需要在main函数前定义数组就可以在函数里直接调用了!
11.旗鼓相当的对手 - 加强版
Code from Luogu:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000+10;
struct Stu{
string name;//人的名字
int c,m,e;//C代表语文,M代表数学,E代表英语
}a[MAXN];//定义结构体
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].name>>a[i].c>>a[i].m>>a[i].e;//输入
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int ans=abs(a[i].c-a[j].c);//每一门分数相减
int ans1=abs(a[i].m-a[j].m);
int ans2=abs(a[i].e-a[j].e);
int ans3=abs(a[i].e+a[i].c+a[i].m-a[j].c -a[j].m-a[j].e);//总分相减
if(ans<=5&&ans1<=5&&ans2<=5&&ans3<=10){//判断是否符合旗鼓相当的对手
if(a[i].name>a[j].name)//判断字典序
cout<<a[j].name<<" "<<a[i].name<<"\n";
else cout<<a[i].name<<" "<<a[j].name<<"\n";
}
}
}
return 0;//结束
}
笔记:
- 这道题思路和之前基本一致,唯一要注意的点是最后输出名字要按字典序,
if(a[i].name>a[j].name)//判断字典序
,原来可以直接通过大于小于来判断。