算法1-1 模拟与高精度

        模拟是最基本的算法思想,也就是按照题目进行模拟。

模拟

第一题:

题目描述

在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于 d-h 或者 4-8 的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为 defgh45678。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:

(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 应输出为 de3-4 应输出为 34。如果减号右边的字符按照 ASCII 码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:d-d 应输出为 d-d3-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;
}

高精度:

        在这里一共学习了三种高精度,高精度乘法,高精度加法,和高精度乘法加法的混合运用,学到了,乘法的新的计算方法:

最初的计算方法:

 改进之后:

 其实就是类似于分配律的东西,精简了不少代码。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值