[LOJ6274]数字

题目

传送门 to usOJ

题意概要
求这个不可重集合的大小:{xyx[lx,rx],y[ly,ry],xy=T}\{x\cap y|x\in[l_x,r_x],y\in[l_y,r_y],x\cup y=T\}

其中 \cap 表示按位与,\cup 表示按位或。

数据范围与提示
所有数据均为 [0,260)[0,2^{60}) 内的整数,同时保证 lxrxl_x\le r_xlyryl_y\le r_y

思路

可以看大佬的博客,并在评论区留下 “湘妹儿~” 的评论 😃

一眼数位 dpdp 题……当然是用二进制考虑。大致思路仅需一眼,具体做法头发掉光 😢

我们来看看这道题到底怎么做。用 dpdp 来做——非常慢的 dpdp 。用 f(i,p,q)f(i,p,q) 表示,仅仅考虑前 i1i-1 位时,xx 的取值为 ppyy 的取值为 qq ,能够拿到多少个不同的按位与的值。不妨用 p=prei(x)p=pre_i(x) 来表示 xx 的前 i1i-1 位为 pp ,那么用数学语言描述就是 f(i,p,q)=card{xyx[lx,rx],y[rx,ry],xy=T,p=prei(x),q=prei(y)}f(i,p,q)=card\{x\cap y|x\in[l_x,r_x],y\in[r_x,r_y],x\cup y=T,p=pre_i(x),q=pre_i(y)\}

毕竟数位 dpdp 嘛 😎

然后我们枚举当前位的取值就很好做了……吗?用 (a0,b0)(a_0,b_0) 表示 xx 的第 ii 位为 a0a_0yy 的第 ii 位为 b0b_0 的情况,那么 (1,0)(1,0)(0,1)(0,1) 是有交集的,因为按位与的值没有出现区别,但是 x,yx,y 的值不一样了。

这两种情况怎么处理?我们给出一个惊世骇俗的结论:二者的方案有包含关系

首先,我们说明一下,既然在这一位上既可以取 (0,1)(0,1) 也可以取 (1,0)(1,0) ,那么取 11 的就一定摆脱下界;取 00 就一定摆脱上界。这个道理很简单,可以取 00 ,那么取 11 就没有顶住下界。严谨证明不给出了,太简单。

如果结论是错误的,那么就有两个不同的按位与的值,分属于两者。也就是:我们试图证明 AABϕA-A\cap B\ne\phiBABϕB-A\cap B\ne\phi ,于是,xA,yB\exist x\in A,y\in B 满足 x∉B,y∉Ax\not\in B,y\not\in A

我们可以假设这个方案真实存在,后面的数字假设出来。对于后面某一个按位或为 11 的位置(因为按位或为 00 的位置没得选 😅),存在三种情况:(0,1),(1,0),(1,1)(0,1),(1,0),(1,1) 。我们都来看一看:

  • (1,0)(1,0) 组合在这里插入图片描述看图片上面所说的,00 可以更改为 11 。这个数字在增大,而前面的 00 让它摆脱了上界,所以不会超出范围。
    同时,第 ii 位的选择仍然是被固定住的。原本前面就没法选 11 ,现在你又增大了一点,就更不能选 11 了!
  • (1,1)(1,1) 组合在这里插入图片描述
    类似地,将 11 更改为 00 是完全可以的。同时,第 ii 位的选择也仍然没有增多。
  • (0,1)(0,1) 组合
    仔细看完,你会发现,(1,0)(1,1)(0,1)(1,0)\rightarrow (1,1)\rightarrow (0,1) ,并且第 ii 位的选择仍然固定。
    那么,倘若真的存在两对方案 (x1,y1),(x2,y2)(x_1,y_1),(x_2,y_2) 并且二者仅仅属于第 ii 位的某一个选择,那么经过这一系列调整,将会得到 (x,y)(x',y') 只能属于 (1,0)(1,0) 也只能属于 (0,1)(0,1) ,矛盾。

我们已经成功除杂了,只需要使用 max(f1,f2)\max(f_1,f_2) 即可,两种情况取最大值。

但是速度有点慢,怎么办呢?原来 p,qp,q 不影响后面的转移,影响转移的是,是否顶住了上下界。改成四个 boolbool 就行了。复杂度变成了 O(25logT)\mathcal O(2^5\log T) ,稳!

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long int_;
inline int_ readint(){
	int_ a = 0; char c = getchar(), f = 1;
	for(; c<'0' or c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c and c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

int_ T, lx, ly, rx, ry, dp[60][2][2][2][2];
# define a_ a|((lx>>x&1) < i)
# define b_ b|(i < (rx>>x&1))
# define c_ c|((ly>>x&1) < j)
# define d_ d|(j < (ry>>x&1))
# define sxy a_,b_,c_,d_
int_ work(int x,int a,int b,int c,int d){
	if(x == -1) // 每一位都被考虑了
		return 1; // 仅有自己一种
	int_ &zxy = dp[x][a][b][c][d];
	if(zxy != -1) return zxy; zxy = 0;
	int_ chose = 0; // 二者取max
	for(int i=0; i<2; ++i)
	for(int j=0; j<2; ++j)
	if((i|j) == (T>>x&1)) // 满足按位或条件
	if(a or (lx>>x&1) <= i) // x下界
	if(b or i <= (rx>>x&1)) // x上界
	if(c or (ly>>x&1) <= j) // y下界
	if(d or j <= (ry>>x&1)) // y上界
		if((a&b) == 1) zxy = work(x-1,sxy);
		else chose = max(chose,work(x-1,sxy));
	return zxy += chose;
}

int main(){
	memset(dp,-1,sizeof dp);
	T = readint();
	lx = readint(), rx = readint();
	ly = readint(), ry = readint();
	printf("%lld\n",work(59,0,0,0,0));
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章