[蓝桥杯][2015年第六届真题]表格计算(递归+记忆化)

题目描述
某次无聊中, atm 发现了一个很老的程序。这个程序的功能类似于 Excel ,它对一个表格进行操作。
不妨设表格有 n 行,每行有 m 个格子。
每个格子的内容可以是一个正整数,也可以是一个公式。
公式包括三种:

  1. SUM(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的和。
  2. AVG(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的平均数。
  3. STD(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的标准差。

标准差即为方差的平方根。
方差就是:每个数据与平均值的差的平方的平均值,用来衡量单个数据离开平均数的程度。

公式都不会出现嵌套。

如果这个格子内是一个数,则这个格子的值等于这个数,否则这个格子的值等于格子公式求值结果。

输入这个表格后,程序会输出每个格子的值。atm 觉得这个程序很好玩,他也想实现一下这个程序。
输入
第一行两个数 n, m 。
接下来 n 行输入一个表格。每行 m 个由空格隔开的字符串,分别表示对应格子的内容。
输入保证不会出现循环依赖的情况,即不会出现两个格子 a 和 b 使得 a 的值依赖 b 的值且 b 的值依赖 a 的值。

输出
输出一个表格,共 n 行,每行 m 个保留两位小数的实数。
数据保证不会有格子的值超过 1e6 。
样例输入
3 2
1 SUM(2,1:3,1)
2 AVG(1,1:1,2)
SUM(1,1:2,1) STD(1,1:2,2)
样例输出
1.00 5.00
2.00 3.00
3.00 1.48
思路:其实这个题目看着比较麻烦,但是思路还是比较好想的。我们利用字符串二维数组先储存起来,然后对于那些没有直接给出的数值,递归去求。求出来之后就将结果保存,以免重复求。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mem(a,b,c) for(int i=1;i<=b;i++) for(int j=1;j<=b;j++) a[i][j]=-1.0;
using namespace std;

const int maxx=101;
string s[maxx][maxx];
double ans[maxx][maxx];
int a[5];
int n,m;

inline double getval(int x,int y)
{
	string t=s[x][y];
	if(ans[x][y]!=-1.0) return ans[x][y];
	if(t[0]>='0'&&t[0]<='9')
	{
		double sum=0.0;
		for(int i=0;i<t.length();i++) sum=sum*10.0+(t[i]-'0');
		return ans[x][y]=sum;
	}
	int num=0,j;
	memset(a,0,sizeof(a));
	for(int i=0;i<t.length();)
	{
		if(t[i]>='0'&&t[i]<='9')
		{
			j=i;
			while(j<t.length()&&t[j]>='0'&&t[j]<='9') a[num]=a[num]*10+(t[j++]-'0');
			i=j;
			num++;
		}
		else i++;
	}
	double sum=0; 
	for(int i=a[0];i<=a[2];i++)
	for(int j=a[1];j<=a[3];j++)
	sum+=getval(i,j);
	if(t[1]=='U') return ans[x][y]=sum;
	else if(t[1]=='V') return ans[x][y]=sum/(double)((a[2]-a[0]+1)*(a[3]-a[1]+1));
	else
	{
		double avg=sum/(double)((a[2]-a[0]+1)*(a[3]-a[1]+1));
		double ans1=0.0;
		for(int i=a[0];i<=a[2];i++)
		for(int j=a[1];j<=a[3];j++)
		{
			double xx=getval(i,j);
			ans1+=(xx-avg)*(xx-avg);
		}
		return ans[x][y]=sqrt(ans1/(double)((a[2]-a[0]+1)*(a[3]-a[1]+1)));
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	mem(ans,n,m);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++) cin>>s[i][j];
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++) ans[i][j]=getval(i,j);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++) 
		printf("%.2lf%c",ans[i][j],j==m?'\n':' ');
	return 0;
}

在这里插入图片描述
努力加油a啊,(o)/~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值