目录
1.洛谷---多项式输出

一项一项输出,每一项输出关心3个部分:符号+系数+次数
- 符号:其他时间不用管,除了第一次输出,如果为正则跳过输出,为负正常输出
- 系数:为 1 时跳过输出,当次数为 0 时,即使为 1 也要正常输出;为 0 时符号一整段跳过输出(break语句)
- 次数:第一个未知数的次数为 n
- 当输出完符号后,系数的符号就没用了,所以可以abs取系数的绝对值
- 字符串变量不能和整型变量相加,c++中未定义过这样的操作
代码:
cpp
#include<iostream>
#include<vector>
#include<string>
#include<cmath>
using namespace std;
string ret;
int main()
{
int n;cin>>n;
vector<int> num(n+1,0);
for(int i=n;i>=0;i--)cin>>num[i];
for(int i=n;i>=0;i--)
{
//系数为0,什么都不用考虑了
if(!num[i]) continue;
else
{
//符号判断
if(num[i]<0) ret+='-';
else
{
if(i!=n) ret+='+';
}
//系数判断
int flag = abs(num[i]);
if(flag!=1||(flag==1&&i==0)) ret+=to_string(flag);
//次数判断
if(i>1) ret = ret + "x^" + to_string(i);
else if(i==1) ret += "x";
}
}
cout<<ret;
return 0;
}
代码易错点:
请注意,x的次数为1时,是不需要加上 ^1 的!
2.洛谷---蛇形方阵

注意事项:注意每个数字有都会占用 3 个字符,前面使用空格补齐
解决思路:
- 定义方向向量:先定义一个坐标轴,因为原点是在左上角,所以需要把整个坐标轴往右旋转90°,如下图1所示;定义两个数组,dx 和 dy ,dx = {0,0,1,-1} dy = {1,-1,0,0} ;此时如果从(2,3)往右走一个单位 -> (2,4)= (2,3)+ dx[0] + dy[0]
- 根据规则结合方向向量填数:朝一个方向走,边走边填数;越界之后,结合方向向量,重新计算出新的坐标以及方向
- 数组从第1行第1列开始算,这样就可以简化很多的数组越界问题
- 边界情况:y <= n && x <= n && x >= 1 && y >= 1 && arr[x][y] == 0
- dx、dy数组最好是以右下左上的顺序出现,并定义一个变量pos,只要不符合上面的边界情况,pos ++;但如果 pos 从最后一个的情况(往上移动,如下图2所示),变回了第1种情况(往右移动),此时数组会越界,所以需要 pos = (pos+1)%4
- 总共要填n行n列个数字,即为 n * n 个数字
- %0 /0 不会编译报错,但在C++中这是未定义行为,通常会导致程序崩溃或死循环

图1

图2
代码:
cpp
#include<iostream>
#include<vector>
using namespace std;
const int N = 30;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};//右下左上
int ret[N][N];
int main()
{
int n;
cin>>n;
int x=1,y=1;//初始位置
int count=1;//当前数值
int pos = 0;
while(count<=n*n)
{
//正常情况
if(y >= 1 && y <= n && x <= n && x >= 1 && ret[x][y] == 0) ret[x][y]=count;
else//越界情况
{
x-=dx[pos];y-=dy[pos];//出现越界了还要退回到原来位置
pos = (pos+1)%4;
count--;//字符还没有填,所以需要和后面那个count++抵消掉
}
x+=dx[pos];y+=dy[pos];
count++;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%3d",ret[i][j]);
cout<<endl;
}
return 0;
}
代码易错点:
如何输出占用3个字符的数字?
printf("%3d",ret[i][j]);
3.洛谷---字符串展开

对于条件很多的模拟题,我们可以把各种条件先写下来
- p1 : =1 -> 填小写 && =2 -> 填大写 && =3 -> 填 * 号
- p2 : =1 -> 填 1 个 && =n -> 填 n 个
- p3 : =1 -> 顺序填写 && =2 -> 逆序填写
同时还有一些注意事项:
当 - 号两边只差了1(例如d和e),那么直接把 - 号去掉就行;当 - 号两边为同一个字符,那么直接原封不动地输出 - 号;如果 - 号左边的字符大于右边的字符,也是直接输出 - 号;当不为 - 号,直接输出即可,因为需要修改填充的只有 - 号;当 - 号出现在字符串开头和结尾,直接输出
代码:
cpp
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int p1,p2,p3;
string a;
string ret;
bool islet(char ch)
{
return ch>='a'&&ch<='z';
}
bool isnum(char ch)
{
return ch>='0'&&ch<='9';
}
void add(char left,char right)
{
//开始展开
string r;
for(char ch=left+1;ch<right;ch++)
{
char tmp = ch;
//处理p1
if(p1==2&&islet(tmp)) tmp-=32;
else if(p1==3)tmp = '*';
//处理p2
for(int turn=1;turn<=p2;turn++)r+=tmp;
}
//处理p3
if(p3==2)reverse(r.begin(),r.end());
ret+=r;
}
int main()
{
cin>>p1>>p2>>p3>>a;
int n = a.size();
for(int i=0;i<=n-1;i++)
{
//不是 - 号,或者 - 号出现在开头和结尾
if(a[i]!='-'||i==0||i==n-1) ret+=a[i];
else
{
char left=a[i-1],right=a[i+1];
//islet函数为判断字符是否为字母,isnum函数为判断字符是否为数字
if((islet(left)&&islet(right)&&right>left)||
(isnum(left)&&isnum(right)&&right>left))
{
//字符串展开
add(left,right);
}
else
{
ret+=a[i];
}
}
}
cout<<ret;
return 0;
}
代码易错点:
写这种模拟题真的会有非常多的条件需要判断,因此我们可以通过函数来进行模块的解耦,最好不要出现屎山代码(会难以调试与理解)
当我们直接cout (a-a+A)时,输出的不会是字符A,而是A的asc码值65
小写字母变大写字母,减去32号即可(a的asc码为97,A的asc码为65)