[LOJ6274] 数字

前言

这是一篇普通博客

失踪人口开学啦!真哒!回归啦!

然而令人窒息的教练使得我依然要鸽题解

题目

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 <cstdio>
#include <cstring>
#include <algorithm>
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 <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>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),嘿嘿嘿

原文地址:https://www.cnblogs.com/PPLPPL/p/13395232.html