2019年蓝桥杯省赛真题 后缀表达式

57 阅读2分钟

自己想的,贪心的去做,给数组排个序,大的在前面,小的在后面,先把大的相加,把加号用完为止,再去减小的,把减号用完为止:

#include<bits/stdc++.h>
using namespace std;

#define int long long
int n,m;
signed  main()
{
  cin.tie(nullptr)->sync_with_stdio(false);
 	cin>>n>>m;
 	int t=n+m+1;
 	vector<int>a(t); 
 	for(int i=0;i<t;i++)cin>>a[i];
 	
 	sort(a.begin(),a.end(),greater<int>());
 	

 	int sum=a[0];
 	int i=1;

	while(n--)
 	{
 	   sum+=a[i];
 	 
	    i++;
	}
	
	int j=i;
	while(m--)
	{
		sum-=a[j];
		j++;
	}
	
	cout<<sum;
	return 0;
} 

只过了30%,wa错误: image.png

优化

例如 - - + 1 2 3 4,按照上面的思路是这样求的:->4+3-1-2=4。

但是实际上这样求出来并不是最大值。我可以这样求:-> 4+3-(1-2)

这样开出来就是:->4+3-1+2=8

其二,数组中存在元素是负数的可能。例如

而存在负数又有两种情况:

1.负数个数比 负号个数少

2.负数个数 和 负号个数一样

但是对于两种情况,我们都可以把它变为a(bcd) a-(b-c-d-……)的形式

例如:

(1) - - + 1 -2 3 -4 -> (3 - -4)+( 1 - -2) 可全化为正求和

(2) - - + 1 -2 3 4 -> 4 + 3 - (-2 - 1) 可全化为正求和

因此无论有多少个操作符,操作数是否有负数,我们都可以看一下是否有负号,如果没有负号,那么只需要全部相加即可。

如果有负号,那么我们就可以转化为 a-(b-c-d-……)的形式。

其中最多只会减去一个数,其他的都会转化求和的形式。

为了使整体值最大,我们要使这个减去的数最小,因此,我们可以对数组排个序,然后减去第一个数即可。

code

因为a[i]最大1e9,所以记得开long long,不然只能过70%

数值的个数是操作符的个数和+1,操作符个数最大1e5,所以数字数组要开2e5,不然只能过70%

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
int a[N];
signed main()
{
  int n,m;cin>>n>>m;

  int k=n+m+1;

for(int i=1;i<=k;i++)cin>>a[i];

sort(a+1,a+k+1);

 int ans=0; 
//如果没有减号直接相加即可 
if(m==0)
{
  for(int i=1;i<=k;i++)
  ans+=a[i];
}

else
{
	//最大值 - 最小值  其余的所有负数全部变为正数相加形式
    ans=a[k]-a[1];
	for(int i=2;i<k;i++)
	{
		ans+=abs(a[i]);
	}	
}

cout<<ans<<endl;

  return 0;
}