【NOIP】普及组2011 表达式的值

【算法】动态规划+后缀表达式

【题解】

先把算式转为后缀表达式后进行DP

令f[s][0]表示使表达式答案为0的方案数

f[s][1]表示使表达式答案为1的方案数

(加法)

f[a+b][1]=f[a][0]*f[b][1]+f[a][1]*f[b][0]+f[a][1]*f[b][1]
f[a+b][0]=f[a][0]*f[b][0]

(乘法)

f[a+b][0]=f[a][0]*f[b][0]+f[a][0]*f[b][1]+f[a][1]*f[b][0]
f[a+b][1]=f[a][1]*f[b][1]

【后缀表达式】

1.对符号设置优先级,即先计算的符号,一般是 () > * > + 。

2.从前往后扫描,遇到数字入数字栈顶,遇到符号入符号栈顶。

如果当前符号优先级低于栈顶符号,那么弹出栈顶符号并对数字栈顶和次顶弹出做该符号运算,结果重新作为数字栈顶。

重复直至优先级高于栈顶符号或栈空。

3.遇到左括号直接入栈,遇到右括号弹出符号栈顶直至左括号停止。

为了最后能清空符号栈,通常最开始加入左括号,最后加入右括号。

4.本题的DP其实是对数字栈DP,每次运算时对应变换DP数组f[]。

我的代码中的写法是先处理出后缀表达式(数字直接放,符号压栈),然后再用后缀表达式模拟数字栈变化。

【注意】

1.记得取模10007。

2.调试几小时的教训!在计算“+”的f[a+b][1]的时候调用了f[a+b][0],所以一定要把f[a+b][1]先计算!!!(“*”反之)T_T调得好累……

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=150010,mod=10007;
char s[maxn*2],t[maxn*2],now[maxn*2],c;
int lenn,lent,len,num,n;
int f[maxn][2];
void jrz()
{
    while(now[lenn]=='+'||now[lenn]=='*')t[++lent]=now[lenn--];
    now[++lenn]='+';
}
void crz()
{
    while(now[lenn]=='*')t[++lent]=now[lenn--];
    now[++lenn]='*';
}
void kcz()
{
    while(now[lenn]!='(')t[++lent]=now[lenn--];
    lenn--;
}
void pluss()
{
    f[num][1]=(f[num][0]*f[num+1][1]+f[num][1]*f[num+1][0]+f[num][1]*f[num+1][1])%mod;
    f[num][0]=(f[num][0]*f[num+1][0])%mod;
}
void cheng()
{
    f[num][0]=(f[num][0]*f[num+1][1]+f[num][1]*f[num+1][0]+f[num][0]*f[num+1][0])%mod;
    f[num][1]=(f[num][1]*f[num+1][1])%mod;
}
void change()
{
    now[0]='(';lenn=0;lent=-1;
    for(int i=0;i<=len;i++)
     {//printf("%d",i);
     //for(int j=0;j<=lenn;j++)printf("%c",now[j]);
     //printf("   lenn=%d\n",lenn);
         if(s[i]=='_')t[++lent]='_';
         if(s[i]=='+')jrz();
         if(s[i]=='*')crz();
         if(s[i]=='(')now[++lenn]='(';
         if(s[i]==')')kcz();
     }
    kcz();//printf("lenn=%d",lenn);printf("[t]\n\n%s\n\n",t);
}
void work()
{
    num=0;
    for(int i=0;i<=lent;i++)
     {
         if(t[i]=='_')
          {
              num++;
              f[num][0]=1;f[num][1]=1;
          }
         if(t[i]=='+')num--,pluss();//printf("f[%d][0]=%d,f[%d][1]=%d\n",num,f[num][0],num,f[num][1]);
         if(t[i]=='*')num--,cheng();//printf("f[%d][0]=%d,f[%d][1]=%d\n",num,f[num][0],num,f[num][1]);
     }
}
int main()
{
//    freopen("exp.in","r",stdin);
//    freopen("exp.out","w",stdout);
    scanf("%d",&n);
    c=getchar();c=getchar();
    len=-1;
    if(c!='(')s[0]='_',len=0;
    s[++len]=c;
    for(int i=2;i<=n;i++)
     {
         c=getchar();
         if(c!='('&&s[len]!=')')s[++len]='_';
         s[++len]=c;
     }
    if(c!=')')s[++len]='_';
//    printf("\n\n%s\n\n",s);
    change();
    work();
    printf("%d",f[1][0]);
    return 0;
}
View Code

 

posted @ 2016-08-13 20:23  ONION_CYC  阅读(970)  评论(1编辑  收藏  举报