1. 程式人生 > >表示式(exp) - 表示式求值 - 搜尋

表示式(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));
}