模拟是最基本的算法思想,也就是按照题目进行模拟。
模拟
第一题:
题目描述
在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于 d-h
或者 4-8
的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为 defgh
和 45678
。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:
(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号 -
,减号两侧同为小写字母或同为数字,且按照 ASCII
码的顺序,减号右边的字符严格大于左边的字符。
(2) 参数 p1p1:展开方式。p1=1p1=1 时,对于字母子串,填充小写字母;p1=2p1=2 时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。p1=3p1=3 时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号 *
来填充。
(3) 参数 p2p2:填充字符的重复个数。p2=kp2=k 表示同一个字符要连续填充 kk 个。例如,当 p2=3p2=3 时,子串d-h
应扩展为 deeefffgggh
。减号两边的字符不变。
(4) 参数 p3p3:是否改为逆序:p3=1p3=1 表示维持原来顺序,p3=2p3=2 表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如当 p1=1p1=1、p2=2p2=2、p3=2p3=2 时,子串 d-h
应扩展为 dggffeeh
。
(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:d-e
应输出为 de
,3-4
应输出为 34
。如果减号右边的字符按照 ASCII
码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:d-d
应输出为 d-d
,3-1
应输出为 3-1
。
输入格式
共两行。
第 11 行为用空格隔开的 33 个正整数,依次表示参数 p1,p2,p3p1,p2,p3。
第 22 行为一行字符串,仅由数字、小写字母和减号 -
组成。行首和行末均无空格。
输出格式
共一行,为展开后的字符串。
输入输出样例
输入 #1
1 2 1 abcs-w1234-9s-4zz
输出 #1
abcsttuuvvw1234556677889s-4zz
输入 #2
2 3 2 a-d-d
输出 #2
aCCCBBBd-d
说明/提示
40%40% 的数据满足:字符串长度不超过 55。
100%100% 的数据满足:1≤p1≤3,1≤p2≤8,1≤p3≤21≤p1≤3,1≤p2≤8,1≤p3≤2。字符串长度不超过 100100。
题目分析:
显而易见,此题只需要模拟达到题目的要求即可,下面分析几个坑点:
1.关于“ - ”的前后不一致,是数字和字母混合,所以,要分三个的大情况:前后都是数字,前后都是字母,再else
2.再层层进行进行if——else的嵌套,每种情况都要面面俱到
3.要注意-的出现与否,当front+1==next的时候不能输出-,相等时要输出
代码:
#include <stdio.h>
#include <string.h>
//学到:关于将情况分析透彻的思想
char string[1010];
int main() {
int p1,p2,p3;
scanf("%d %d %d",&p1,&p2,&p3);
scanf("%s",string);
int len=strlen(string);
char front,next;
for(int i=0; i<len; i++) {
if(string[i]!='-') {
printf("%c",string[i]);
} else {
front=string[i-1];
next=string[i+1];
//分3种情况:
//1.前后是数字:判断是否反序,输出
//2.前后是字母 :判断是否大写,然后判断是否反序 ,输出
//3.前是字母,后是字母:直接continue;
if(front+1==next) {
continue;
}
if(front==next) {
printf("-");
continue;
}
if(front<next) {
if(front>=48&&front<=57&&next>=48&&next<=57) {
if(p1==1||p1==2) {
if(p3==1) {
for(int k=front+1; k<next; k++) {
for(int j=0; j<p2; j++) {
printf("%c",k);
}
}
} else if(p3==2) {
for(int k=next-1; k>front; k--) {
for(int j=0; j<p2; j++) {
printf("%c",k);
}
}
}
} else {
for(int k=front+1; k<next; k++) {
for(int j=0; j<p2; j++) {
printf("*");
}
}
}
} else if(next>=97&&next<=122&&front>=97&&front<=122) {
if(p1==1) {
if(p3==1) {
for(int k=front+1; k<next; k++) {
for(int j=0; j<p2; j++) {
printf("%c",k);
}
}
} else if(p3==2) {
for(int k=next-1; k>front; k--) {
for(int j=0; j<p2; j++) {
printf("%c",k);
}
}
}
} else if(p1==2) { //执行大写字母
if(p3==1) {
for(int k=front+1; k<next; k++) {
for(int j=0; j<p2; j++) {
printf("%c",k-32);
}
}
} else if(p3==2) {
for(int k=next-1; k>front; k--) {
for(int j=0; j<p2; j++) {
printf("%c",k-32);
}
}
}
} else {
for(int k=front+1; k<next; k++) {
for(int j=0; j<p2; j++) {
printf("*");
}
}
}
} else {
printf("-");
continue;
}
} else {
printf("-");
continue;
}
}
}
}
第二题:
题目描述
Scarlet 最近学会了一个数组魔法,她会在 n×nn×n 二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转 90∘90∘。
首先,Scarlet 会把 11 到 n2n2 的正整数按照从左往右,从上至下的顺序填入初始的二维数组中,然后她会施放一些简易的魔法。
Scarlet 既不会什么分块特技,也不会什么 Splay 套 Splay,她现在提供给你她的魔法执行顺序,想让你来告诉她魔法按次执行完毕后的二维数组。
输入格式
第一行两个整数 n,mn,m,表示方阵大小和魔法施放次数。
接下来 mm 行,每行 44 个整数 x,y,r,zx,y,r,z,表示在这次魔法中,Scarlet 会把以第 xx 行第 yy 列为中心的 2r+12r+1 阶矩阵按照某种时针方向旋转,其中 z=0z=0 表示顺时针,z=1z=1 表示逆时针。
输出格式
输出 nn 行,每行 nn 个用空格隔开的数,表示最终所得的矩阵
输入输出样例
输入 #1
5 4 2 2 1 0 3 3 1 1 4 4 1 0 3 3 2 1
输出 #1
5 10 3 18 15 4 19 8 17 20 1 14 23 24 25 6 9 2 7 22 11 12 13 16 21
题目分析:
此题最重要的是如何实现旋转,和多阶旋转,其实,旋转的时候,将旋转中心当作是(0,0),也就是坐标原点,已经和平面直角坐标系联系起来,(i,j)逆时针旋转得到坐标为(-j,i),(注意此时的坐标系就是平面直角坐标系,而不是所谓二维数组构建的坐标系,实际上是:在二维数组构建的坐标系里构建的平面直角坐标系),
所以有:
其中r是旋转的阶数,而x和y是中心点在二维数组坐标系的坐标,temp是临时数组,而num是保存数据的数组,达到题目要求之后,直接对应相等即可
for(int i=-r; i<=r; i++) { //外部确定进行操作行数, 内部确定进行操作的列数
for(int j=-r; j<=r; j++) {
temp[x-j][y+i]=num[i+x][j+y];
}
}
for(int i=x-r; i<=x+r; i++) {
for(int j=y-r; j<=y+r; j++) {
num[i][j]=temp[i][j];
}
}
顺时针也可以通过推导
最终答案:
代码:
#include <stdio.h>
//顺时针:将一个坐标顺时针旋转90°,假设,旋转的核心是坐标x,y则顺时针旋转之后,是y,-x,每一个坐标,假设
//x,y是原点0,0,所以整体加减同一对数对, 得到的数对就是旋转之后的答案
int num[510][510],temp[510][510];
int count;
int main() {
int n,m;
scanf("%d %d", &n,&m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
count++;
num[i][j] = count;
}
}
// for (int i = 1; i <= n; i++) {
// for (int j = 1; j <= n; j++) {
// printf("%d ", num[i][j]);
// }
// printf("\n");
// }
while(m--!=0) {
int x,y,r,w;
scanf("%d %d %d %d",&x,&y,&r,&w);
if(w) {
for(int i=-r; i<=r; i++) { //外部确定进行操作行数, 内部确定进行操作的列数
for(int j=-r; j<=r; j++) {
temp[x-j][y+i]=num[i+x][j+y];
}
}
for(int i=x-r; i<=x+r; i++) {
for(int j=y-r; j<=y+r; j++) {
num[i][j]=temp[i][j];
}
}
} else {
for(int i=-r; i<=r; i++) { //外部确定进行操作行数, 内部确定进行操作的列数
for(int j=-r; j<=r; j++) {
temp[x+j][y-i]=num[i+x][j+y];
}
}
for(int i=x-r; i<=x+r; i++) {
for(int j=y-r; j<=y+r; j++) {
num[i][j]=temp[i][j];
}
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
printf("%d ", num[i][j]);
}
printf("\n");
}
return 0;
}
高精度:
在这里一共学习了三种高精度,高精度乘法,高精度加法,和高精度乘法加法的混合运用,学到了,乘法的新的计算方法:
最初的计算方法:
改进之后:
其实就是类似于分配律的东西,精简了不少代码。