题目描述:
已知 T,Lx,Rx,Ly,Ry T , L x , R x , L y , R y ,问在满足 Lx≤x≤Rx,Ly≤y≤Ry,x or y=T L x ≤ x ≤ R x , L y ≤ y ≤ R y , x o r y = T 的情况下, W=x and y W = x a n d y 有多少种取值。
解题思路:
数位 DP 会变得比较方便。
考虑一个数 W,我们要判断是否存在一组 (x,y) 使得 Lx ≤ x ≤ R x ,Ly ≤ y ≤ R y 且
x ∨ y = T,x ∧ y = W。
这个过程就是从高位到低位构造 (x,y) 的过程。
• 若 T 的当前位为 0,W 的当前位为 0,则 x 和 y 当前位都填 0。
• 若 T 的当前位为 0,W 的当前位为 1,则这是一个不合法的状况。
• 若 T 的当前位为 1,W 的当前位为 0,则当前位上可能 x 填 0,y 填 1,
也可能 x 填 1,y 填 0。
• 若 T 的当前位为 1,W 的当前位为 1,则 x 和 y 当前位都填 1。
x 和 y 各自已经填了的部分可能挨着Rx与 Ry或Lx与Ly的上界 (即 x 或 y 的已填部
分是 R x 或 R y或Lx或Ly 的前缀),也可能不挨,这样就有 3 × 3 = 9 种状态。
之前提到的第三种情况,同一步有两种填法,会造成分叉,所以,如果我们
要判断一个 W 是否可行,在从高位到低位确定 x,y 的过程中,就需要把这9
种状态分别可不可能出现记下来,这是一个 9 位的二进制数。
如何用 DP 的方式算出可行的 W 的种数呢?DP 的状态是当前已经考虑过
的位数和那个 9 位的二进制数。时间复杂度 O(logT),常数为 512。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=65;
ll T,l1,l2,r1,r2,f[N][1<<9];
int cnt,g[3][3];
pair<int,int> sta[9];
ll dfs(int i,int s)
{
if(i==-1)return 1;
if(f[i][s]!=-1)return f[i][s];
ll res=0;
for(int p=0;p<=(T>>i&1);p++)
{
int cur=0;
for(int x=0;x<=1;x++)
for(int y=0;y<=1;y++)if((x|y)==(T>>i&1)&&(x&y)==p)
for(int k=0;k<9;k++)if(s>>k&1)
{
int o1=sta[k].first,o2=sta[k].second;
ll k1,k2;
if(o1==0)k1=r1>>i+1;
else if(o1==1)k1=l1>>i+1;
else k1=(l1>>i+1)+1;
if(o2==0)k2=r2>>i+1;
else if(o2==1)k2=l2>>i+1;
else k2=(l2>>i+1)+1;
k1=(k1<<1)+x;k2=(k2<<1)+y;
if(k1>(r1>>i)||k1<(l1>>i))continue;
if(k2>(r2>>i)||k2<(l2>>i))continue;
if(k1==(r1>>i))o1=0;
else if(k1==(l1>>i))o1=1;
else o1=2;
if(k2==(r2>>i))o2=0;
else if(k2==(l2>>i))o2=1;
else o2=2;
cur|=1<<g[o1][o2];
}
if(cur)res+=dfs(i-1,cur);
}
return f[i][s]=res;
}
int main()
{
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
scanf("%lld%lld%lld%lld%lld",&T,&l1,&r1,&l2,&r2);
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)g[i][j]=cnt,sta[cnt++]=make_pair(i,j);
memset(f,-1,sizeof(f));
cout<<dfs(60,1)<<'\n';
return 0;
}