目錄
題目
分析
我會說這道題最難的其實是讀題嗎???(讀題讀了1h+)
可能是翻譯問題,反正是沒講清楚,我解釋一下:
1.所有類似於"(?)"的表達式的最大值爲Z1(啊啊啊是Z1不是Zi啊)
2.在表達式(()+()+()+......)或者(()*()*()*()*......)中有k項,則這個表達式裏所有元素的總和的最大值爲Zk(是不是被繞暈了)
3.表達式只有全是+或者全是*(不用處理計算的先後問題了)
好了好了,我們終於把題看懂了,下面是做法:
首先,用棧的方式來處理括號其實就是用函數遞歸了。
然後,在函數內部,用數組來儲存其中的k個表達式的最大值
最後呢,就是在每一個括號內部,計算目前括號的最大值。
下面是處理乘法的方式:
衆所周知,
顯然,
可以證明,在總和爲sum的k個數中,要使得它們的乘積最大,要使它們平均分配纔可以。
(平均分配:每個數都是sum/k)
但是,還有一個問題,就是我們有的元素有最大值啊。
那我們就還是儘量平均分配,取不到sum/k的就取它的最大值,然後把它差的數,添到其它數上面(乾坤大挪移!!!)
代碼
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
const int N=50,L=1e6;
int k,len,p=1;
double z[N+5];
char sca[L+5];
double Calc()
{
if(sca[p++] != '(') return 0;
vector<double> c;
bool f=0; //0->+,1->*
char now;
while(now = sca[p++])
{
if(now=='(')
p--,c.push_back(Calc());
if(now=='?')
c.push_back(z[1]);
if(now=='+')
f=0;
if(now=='*')
f=1;
if(now==')')
{
if(!f)
{
double r1=0,r2=0;
r1=z[c.size()];
for(int i=c.size()-1;i>=0;i--)
r2+=c[i];
return min(r1,r2);
}
else
{
int siz=c.size(),cntno=0;
bool vis[N+5];
double maxi=z[c.size()]/siz,ans[N+5];
memset(vis,0,sizeof vis);
for(int i=0;i<siz;i++)
if(!vis[i])
{
if(c[i] < maxi)
{
ans[i] = c[i];
vis[i]=1;
cntno++;
maxi += (maxi-c[i])/(siz-cntno);
i=-1;
continue;
}
else
ans[i]=maxi;
}
double res=ans[0];
for(int i=1;i<siz;i++)
res *= ans[i];
return res;
}
}
}
}
int main()
{
// freopen("kvalitetni.in","r",stdin);
// freopen("kvalitetni.out","w",stdout);
scanf("%d",&k);
for(int i=1;i<=k;i++)
scanf("%lf",&z[i]);
scanf("\n%s",sca+1);
len=strlen(sca+1);
double ans=Calc();
printf("%.6f\n",ans);
return 0;
}