LOJ 6274数字

前言

这是一篇普通博客

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

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

题目

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\),嘿嘿嘿

你可能感兴趣的:(LOJ 6274数字)