前言
这是一篇普通博客
失踪人口开学啦!真哒!回归啦!
然而令人窒息的教练使得我依然要鸽题解
题目
USOJ
LOJ
讲解
一眼数位DP
但众所周知,数位DP的题怎么能用数位DP做呢 (我就没这么过过题)
所以我们使用我最喜欢的搜索!当然是记忆化搜索
定义\(dp[i][lx][rx][ly][ry]\)表示状态在第\(i\)位(二进制下),\(x\)和\(y\)是否各自抵着他们各自的上下界的方案数
我们定义\(V\)是最后按位与起来的答案其中一个
特殊的,我们考虑边界,也就是\(i=0\)时,当然就是具体的一种情况,返回\(1\)
普通的,我们考虑当前位置\(i\)
要满足\(x_i \lor y_i = T_i\)
如果\(x_i \land y_i = V_i\)
很明显,当\(V_i=0\)时,有\(00,01,10\)三种情况,当然我们要选择\(3\)个当中的最大值来转移当前位置
当\(V_i=1\),只有\(11\)一种情况,所以直接累加就好了
至于\(lx,rx,ly,ry,T_i\),这些只是限制条件,用来判断是否可以转移,在过程中顺便处理一下就好了
没听懂就看看代码,挺简单的
代码
//12252024832524
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN = 65;
int n;
int t[MAXN],LX[MAXN],RX[MAXN],LY[MAXN],RY[MAXN];
int dx[4] = {1,1},dy[4] = {0,1,0,1};
LL dp[MAXN][2][2][2][2];
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
void Put1(LL x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
void Put(LL x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x);
if(c >= 0) putchar(c);
}
template T Max(T x,T y){return x > y ? x : y;}
template T Min(T x,T y){return x < y ? x : y;}
template T Abs(T x){return x < 0 ? -x : x;}
void work(int *a,LL val)
{
int len = 0;
while(val) a[++len] = val % 2,val >>= 1;
n = Max(n,len);
}
LL dfs(int x,bool lx,bool rx,bool ly,bool ry)
{
if(!x) return 1;
if(dp[x][lx][rx][ly][ry] != -1) return dp[x][lx][rx][ly][ry];
dp[x][lx][rx][ly][ry] = 0;
LL MAX = 0;
for(int i = 0;i < 4;++ i)
{
int t1 = dx[i],t2 = dy[i];
if((t1 | t2) != t[x]) continue;
if(lx && t1 < LX[x]) continue;
if(rx && t1 > RX[x]) continue;
if(ly && t2 < LY[x]) continue;
if(ry && t2 > RY[x]) continue;
bool p1 = (lx && LX[x] == t1),p2 = (rx && RX[x] == t1),p3 = (ly && LY[x] == t2),p4 = (ry && RY[x] == t2);
if(!(t1&t2)) MAX = Max(MAX,dfs(x-1,p1,p2,p3,p4));//按位与起来是0,有00,01,10三种情况,要取最大值
else dp[x][lx][rx][ly][ry] += dfs(x-1,p1,p2,p3,p4);//就这一种情况啊,当然要累加
}
dp[x][lx][rx][ly][ry] += MAX;
return dp[x][lx][rx][ly][ry];
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
memset(dp,-1,sizeof(dp));
work(t,Read());
work(LX,Read());
work(RX,Read());
work(LY,Read());
work(RY,Read());
Put(dfs(n,1,1,1,1));
return 0;
}
后记
\(loj\)跑了\(Rank1\),\(72ms\),嘿嘿嘿