表达式(exp) - 表达式求值 - 搜索

题目大意:
给定n(=7)和s,以及一个表达式(仅有 a i , < , & , , ( , ) a_i,<,\&,|,(,) 组成,并且先算括号,再算与,再算或,逻辑运算两端一定是真假值,小于号两端一定是数字,并且小于运算结果是真假值,并且括号内一定是真假值),问有多少 { a n } \{a_n\} 满足 a i [ 0 , s ) a_i\in [0,s) ,使得表达式的值是 t r u e \mathrm{true}
题解:
a < b a<b 看做一个真假值(只不过到底是真是假待定)。
枚举排列 p p 以及中间的符号,例如其中一种情况可以是:
a p 1 a p 2 < a p 3 a p 4 a p 5 < a p n a_{p_1}\le a_{p_2}<a_{p_3}\le a_{p_4}\le a_{p_5}\dots< a_{p_n}
(注意去重的问题)。
计算在这种情况下有多少种方案。显然只取决于其是否合法,以及等号数量。
前者由于已经可以确定任意两个数的大小关系,所以所有表达式中的 a < b a<b 都可以被确定为 t r u e \mathrm{true} 或者 f a l s e \mathrm{false} ,然后表达式求值一下即可。
关于表达式求值,先将中缀表达式转为后缀表达式。
转的方法是,若其为操作数,直接放队尾;若其为左括号,放入运算符栈;若其为右括号,则弹出栈顶并放入队尾直到左括号;否则若其优先级小于等于栈顶,则将栈顶弹出并放入队尾,直到栈空或者栈顶运算符为括号或者优先级小于当前运算符,并将该运算符放入栈中。最终若栈不空,则依次退栈并放入队尾即可。
表达式求值就是维护数值栈,每次遇到一个运算符就把栈顶和栈顶的下一个元素合并(并弹出),再放回栈顶。最后栈顶就是答案。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define mod 1000000007
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
using namespace std;const int N=100,M=9;typedef pair<int,int> pii;inline int cti(char c) { return c-'a'+1; }
pii q[N];int rp,top,stc[N],lst[N],ps[M],g[M][M],p[M],u[M],a[M],sz[N],C[M];char str[N];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int calc(int n,int s) { int ans=1;rep(i,1,n) ans=ans*(s-i+1ll)%mod,ans=(lint)ans*fast_pow(i,mod-2)%mod;return ans; }
inline int ok(int *p,int n)
{
    rep(i,1,n) { ps[p[i]]=i,g[i][i]=1;for(int j=i+1,k=a[i];j<=n;k&=a[j++]) g[i][j]=k; } top=0;int x,y;
    rep(i,1,rp) q[i].fir?(((x=ps[q[i].fir])>(y=ps[q[i].sec]))?lst[i]=0:(lst[i]=(g[x][y]==0))):(lst[i]=q[i].sec);
    rep(i,1,rp) (lst[i]<=1)?stc[++top]=lst[i]:(stc[top-1]=(lst[i]=='&'?(stc[top]&stc[top-1]):(stc[top]|stc[top-1])),top--);
    return stc[1];
}
int dfs(int x,int n,int ans=0)
{ for(p[x]=(a[x-1]?p[x-1]+1:1);p[x]<=n;p[x]++) if(!u[p[x]]) u[p[x]]=1,(x==n?ans+=ok(p,n):ans+=dfs(x+1,n)),u[p[x]]=0;return ans; }
int main()
{
    int s=0,t=0,n=7,all=(1<<(n-1))-1;rep(i,1,all) sz[i]=sz[i^(i&-i)]+1;
    for(int c,las=0;c=gc;)
        if(c>='a'&&c<='a'+n-1) (las?q[++rp]=mp(cti(las),cti(c)),las=0:(las=c));
        else if(c=='(') stc[++top]=c;
        else if(c==')') { while(stc[top]!='(') q[++rp]=mp(0,stc[top]),top--;top--; }
        else if(c=='&') { while(top&&stc[top]=='&') q[++rp]=mp(0,stc[top]),top--;stc[++top]='&'; }
        else if(c=='|') { while(top&&(stc[top]=='|'||stc[top]=='&')) q[++rp]=mp(0,stc[top]),top--;stc[++top]='|'; }
        else if(c>='0'&&c<='9') { s=c-'0';break; }
        else continue;
    while(top) q[++rp]=mp(0,stc[top]),top--;
    for(int c;c=gc;s=s*10+(c-'0')) if(c<'0'||c>'9') break;
    rep(i,1,n) C[i]=calc(i,s);lint ans=0;
    rep(i,0,all) { rep(j,1,n-1) a[j]=((i>>(j-1))&1);ans+=(lint)C[n-sz[i]]*dfs(1,n)%mod; }
    return !printf("%d\n",(int)(ans%mod));
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83058449