先考慮另外一個問題:在上下界限制下判斷是否存在 \(x,y\) 知足 \(x \or y=v_1,x \and y=v_2\),設 \(f(p,a,b,c,d)\) 表示考慮到第 \(p\) 位和上下界限制是否合法。回到原問題,考慮 \(DP\) 套 \(DP\),設 \(g(p,S)\) 表示考慮到第 \(p\) 位,\(DP\) 狀態爲 \(S\) 的 \(v_2\) 個數,其中 \(S\) 是將上一個 \(DP\) 後四維中 \(2^4\) 種狀況壓起來,枚舉 \(v_2\) 當前位的值便可轉移。複雜度爲 \(O(2^{16}\log T)\)。c++
也能夠直接數位 \(DP\),注意當前位與爲 \(0\) 時有三種狀況:\(0\ 0,0\ 1,1\ 0\),都加起來會算重,發現方案數小的狀況必定是方案數大的狀況的子集,因而取 \(\max\) 轉移便可。複雜度爲 \(O(2^4\log T)\)。git
\(DP\) 套 \(DP\):spa
#include<bits/stdc++.h> #define maxn 62 #define maxm 65546 #define all 65535 using namespace std; typedef long long ll; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } ll ans; int w[maxn],Lx[maxn],Rx[maxn],Ly[maxn],Ry[maxn]; ll f[maxn][maxm]; int sta(int a,int b,int c,int d) { return (a<<3)|(b<<2)|(c<<1)|d; } void work(int *a) { ll v; int cnt=-1; read(v); while(v) a[++cnt]=v%2,v/=2; } int main() { work(w),work(Lx),work(Rx),work(Ly),work(Ry),f[60][1<<sta(1,1,1,1)]=1; for(int p=59;p>=0;--p) { for(int s=0;s<=all;++s) { if(!f[p+1][s]) continue; for(int v=0;v<=1;++v) { int t=0; for(int a=0;a<=1;++a) { for(int b=0;b<=1;++b) { for(int c=0;c<=1;++c) { for(int d=0;d<=1;++d) { if(!((s>>sta(a,b,c,d))&1)) continue; for(int x=0;x<=1;++x) { for(int y=0;y<=1;++y) { if((x|y)!=w[p]||(x&y)!=v) continue; if(a&&x<Lx[p]) continue; if(b&&x>Rx[p]) continue; if(c&&y<Ly[p]) continue; if(d&&y>Ry[p]) continue; t|=1<<sta(a&(x==Lx[p]),b&(x==Rx[p]),c&(y==Ly[p]),d&(y==Ry[p])); } } } } } } f[p][t]+=f[p+1][s]; } } } for(int i=1;i<=all;++i) ans+=f[0][i]; printf("%lld",ans); return 0; }
數位 \(DP\):code
#include<bits/stdc++.h> #define maxn 62 using namespace std; typedef long long ll; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n; int t[maxn],Lx[maxn],Rx[maxn],Ly[maxn],Ry[maxn]; ll f[maxn][2][2][2][2]; ll dp(int p,bool lx,bool rx,bool ly,bool ry) { if(p==-1) return 1; if(f[p][lx][rx][ly][ry]!=-1) return f[p][lx][rx][ly][ry]; ll v=0,mx=0; for(int i=0;i<4;++i) { int x=i&1,y=i>>1; if((x|y)!=t[p]) continue; if(lx&&x<Lx[p]) continue; if(rx&&x>Rx[p]) continue; if(ly&&y<Ly[p]) continue; if(ry&&y>Ry[p]) continue; bool t1=lx&(x==Lx[p]),t2=rx&(x==Rx[p]),t3=ly&(y==Ly[p]),t4=ry&(y==Ry[p]); if(x&y) v+=dp(p-1,t1,t2,t3,t4); else mx=max(mx,dp(p-1,t1,t2,t3,t4)); } return f[p][lx][rx][ly][ry]=v+mx; } void work(int *a) { ll v; int cnt=-1; read(v); while(v) a[++cnt]=v%2,v/=2; n=max(n,cnt); } int main() { work(t),work(Lx),work(Rx),work(Ly),work(Ry); memset(f,-1,sizeof(f)),printf("%lld",dp(n,1,1,1,1)); return 0; }