[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章