簡要題意:
你有兩種可用的邏輯符號,分別是 和 。
現在有 個獨立的命題變元,和一個未知的公式 ,你只知道 當中總共個存在恰好 個上述邏輯符號,且僅會存在上述 個命題變元。
有 個詢問。每次給出一個公式 ,且 的若干部分可能被 取代。
詢問有多少種可能的 使得 永真。
題解:
本來還以爲要轉成析取範式或者合取範式來搞,仔細一想發現不可實現。
發現 只有 ,也就是說 中命題變元取值情況可以暴力枚舉,然後看允許 取哪些情況。
發現 也就 可以接受,於是考慮對所有 中取值情況下 的值進行狀壓。
很容易想到DP處理,有兩種情況,一種是前面加一個 ,一種是用 連接兩個公式。第一種直接轉移即可,第二種是一個卷積。
乍一看轉移的下標有點詭異,是 ,其實把真值表寫出來就會發現就是
寫個FWT,中途多用點值轉移,不然複雜度是假的。
然後就是枚舉點值暴力模擬計算即可,我轉了一下後綴表達式。
複雜度爲 。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,int b){int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;}
cs int N=77,SIZE=1<<(1<<4)|7;
int n,k,S;
int f[N][SIZE],g[N][SIZE],h[N][SIZE];
int A[SIZE],B[SIZE];
void FWT(int *A){
for(int re i=1;i<S;i<<=1)
for(int re j=0;j<S;j+=i<<1)
for(int re k=0;k<i;++k)
Inc(A[i+j+k],A[j+k]);
}
void IFWT(int *A){
for(int re i=1;i<S;i<<=1)
for(int re j=0;j<S;j+=i<<1)
for(int re k=0;k<i;++k)
Dec(A[i+j+k],A[j+k]);
}
void init(){
for(int re i=0;i<k;++i){
int s=0;
for(int re t=0;t<(1<<k);++t)
s|=((t>>i)&1)<<t;
++f[0][s];
}
for(int re i=0;i<=n;++i){
if(i){
IFWT(f[i]);
for(int re s=0;s<S;++s)
Inc(f[i][s],f[i-1][s^(S-1)]);
}
memcpy(h[i],f[i],S<<2);
memcpy(g[i],f[i],S<<2);
std::reverse(h[i],h[i]+S);
FWT(h[i]),FWT(g[i]);
for(int re j=0;j<=i&&i+j+1<=n;++j)
for(int re s=0;s<S;++s){
Inc(f[i+j+1][s],mul(h[i][s],g[j][s]));
if(i!=j)Inc(f[i+j+1][s],mul(g[i][s],h[j][s]));
}
}
}
int tp;
char s[10000];
std::string get_st(){
scanf("%s",s+1);tp=0;
int len=strlen(s+1);
for(int re i=1;i<=len;++i)
if(s[i]!='x'&&s[i]!='-')
s[++tp]=s[i];
static std::map<char,int> op=
{{'(',0},{')',0},{'>',1},{'~',2}};
std::stack<char,std::vector<char>> stk;std::string st;
for(int re i=1;i<=tp;++i){
char c=s[i];if(isdigit(c))--c;
if(!op.count(c)){
st+=c;
if(!stk.empty()&&stk.top()=='~')
st+=stk.top(),stk.pop();
}else {
if(c==')'){
while(stk.top()!='(')
st+=stk.top(),stk.pop();
stk.pop();
if(!stk.empty()&&stk.top()=='~')
st+=stk.top(),stk.pop();
}else stk.push(c);
}
}
while(!stk.empty())
st+=stk.top(),stk.pop();
return st;
}
bool calc(cs std::string &st,int s,int Q){
std::stack<bool,std::vector<bool> > stk;
for(char c:st){
if(c=='~'){
bool t=stk.top();stk.pop();
stk.push(!t);
}else if(c=='>'){
bool t=stk.top();stk.pop();
bool s=stk.top();stk.pop();
stk.push(!s||t);
}else {
if(isdigit(c))stk.push((s>>(c^48))&1);
else stk.push(Q);
}
}return stk.top();
}
int ans;
bool ok[20][2];
void dfs(int i,int st){
if(i==(1<<k)){Inc(ans,f[n][st]);return;}
if(ok[i][0])dfs(i+1,st);if(ok[i][1])dfs(i+1,st|(1<<i));
}
void solve(){
auto st=get_st();
for(int re s=0;s<(1<<k);++s)
ok[s][0]=calc(st,s,0),
ok[s][1]=calc(st,s,1);
ans=0;dfs(0,0);cout<<ans<<"\n";
}
void Main(){
scanf("%d%d",&n,&k);
S=1<<(1<<k);init();
int m;scanf("%d",&m);
while(m--)solve();
}
inline void file(){
#ifdef zxyoi
freopen("calculus.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("calculus.in","r",stdin);
freopen("calculus.out","w",stdout);
#endif
#endif
}signed main(){file();Main();return 0;}