zoukankan      html  css  js  c++  java
  • 【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
    ",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]
    
    %s
    
    ",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
    ",num,f[num][0],num,f[num][1]);
             if(t[i]=='*')num--,cheng();//printf("f[%d][0]=%d,f[%d][1]=%d
    ",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("
    
    %s
    
    ",s);
        change();
        work();
        printf("%d",f[1][0]);
        return 0;
    }
    View Code
  • 相关阅读:
    IE的if条件判断
    嵌套div的margin-top不生效
    DocumentFragment对象
    javascript严格模式
    某视频网站下载分析
    c# winform 视频转字符动画
    asp.net mvc 5 蛋疼的问题
    asp.net mvc 防止重复提交
    easyHOOK socket send recv
    C# 之泛型详解
  • 原文地址:https://www.cnblogs.com/onioncyc/p/5768763.html
Copyright © 2011-2022 走看看