[LOJ6274]数字

题目

传送门 to usOJ

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

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

数据范围与提示
所有数据均为 [ 0 , 2 60 ) [0,2^{60}) [0,260) 内的整数,同时保证 l x ≤ r x l_x\le r_x lxrx l y ≤ r y l_y\le r_y lyry

思路

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

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

我们来看看这道题到底怎么做。用 d p dp dp 来做——非常慢的 d p dp dp 。用 f ( i , p , q ) f(i,p,q) f(i,p,q) 表示,仅仅考虑前 i − 1 i-1 i1 位时, x x x 的取值为 p p p y y y 的取值为 q q q ,能够拿到多少个不同的按位与的值。不妨用 p = p r e i ( x ) p=pre_i(x) p=prei(x) 来表示 x x x 的前 i − 1 i-1 i1 位为 p p p ,那么用数学语言描述就是 f ( i , p , q ) = c a r d { x ∩ y ∣ x ∈ [ l x , r x ] , y ∈ [ r x , r y ] , x ∪ y = T , p = p r e i ( x ) , q = p r e i ( 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)\} f(i,p,q)=card{xyx[lx,rx],y[rx,ry],xy=T,p=prei(x),q=prei(y)}

毕竟数位 d p dp dp 嘛 😎

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

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

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

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

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

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

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

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

代码

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值