神仙题 宏定义 模拟,递归

感谢yzy神仙精辟入里的讲解.

题目描述
c++中可以宏定义max函数.c++中宏定义的max函数如下.
#define MAX(a,b) (a)>(b)?(a):(b)
但是它在调用的时候可能会出现重复计算加法的情况.
比如说调用MAX(2+3,4)的时候会变成(2+3)>(4)?(2+3):(4),那么这里就不止进行了一次的加法运算.
给出一个只含有数字,加号和MAX()函数的表达式,求出它的运算结果,并计算里面运行加法的次数.
样例: MAX(1+1+1,2)+MAX(2,3) 
输出: 6 5
解释: 前面答案是3,后面也是3,加起来得6.
     前面是(1+1+1)>(2)?(1+1+1):(2),很明显进行了4次加法,再加上后面的3一共进行了5次加法.
神仙题解

一开始我毫无头绪,只知道这是一道模拟题却不知从哪里下手.
结果yzy神仙写了一个递归秒了此题,将此题剖析得非常到位.这里来讲一下他的解法.

/*
递归[l,r]区间.如果区间中只有数字,直接返回此数字.
如果在区间中找到了一个不包含于任何一对括号之内的加号,则将此区间分为左右两部分递归求解.
结果就是两边的和,加法的次数是两边之和+1.
如果没有,则区间中只剩下了很多个MAX函数的嵌套.
首先找到最外层的MAX函数中的那个逗号,然后递归两边,按照宏定义的方式比较.
接下来要注意,较大的一边的加法计算要运行两次.
然后全部加起来,输出结果即可.
*/
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=2e5;
char c[yuzu|10];
#define ans first
#define add second
typedef pair<int,int> node;
/*first存储运算结果,second存储加法运行次数.*/
int makenum(int l,int r){//l,r之间表示的那个数字.
int x=0,i;
for (i=l;i<=r;++i) x=x*10+c[i]-'0';
return x;
}

node work(int l,int r){//返回一个pair
int i,le;//le表示目前在第几层运算里.
for (i=l;i<=r;++i) if (!isdigit(c[i])) break;
if (i>r) return node(makenum(l,r),0);//全部都是数字,直接返回该数字.
for (i=l,le=0;i<=r;++i){//判断是否存在单独的加号.
  if (c[i]=='(') le++;
  if (c[i]==')') le--;
  if (!le&&c[i]=='+') break;//le为0表示现在没有在任何一对括号里.
  }
if (i<=r){//有单独加号
  node a=work(l,i-1),b=work(i+1,r);//分别计算两边.
  return node(a.ans+b.ans,a.add+b.add+1);//两边相加,注意加法的次数要+1.
  }
for (i=l+4,le=0;i<=r;++i){//从l+4开始是因为要跳过"MAX("这一部分.
  if (c[i]=='(') le++;
  if (c[i]==')') le--;
  if (!le&&c[i]==',') break;//寻找最外层的','
  }
node a=work(l+4,i-1),b=work(i+1,r-1);//分别计算比较大小.
return a.ans>b.ans?node(a.ans,a.add*2+b.add):node(b.ans,b.add*2+a.add);
/*ans取较大的那一个,add取较大的那个两倍+小的那个.*/
}

int main(){
scanf("%s",c+1);
int n=strlen(c+1);
node llx=work(1,n);
printf("%d %d",llx.ans,llx.add);//一击必杀.
}

谢谢大家.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值