真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

位運(yùn)算

習(xí)題AcWing216,P2114,例題P4310,K2192(最大and值),P8019

0x01 位運(yùn)算

位運(yùn)算和按位貪心是常用的計(jì)算和優(yōu)化手段。其中,按位枚舉可以將線性級(jí)別的枚舉優(yōu)化至 \(\log\) 級(jí)別;由于二進(jìn)制的獨(dú)特性質(zhì) \(2^0+2^1+\cdots+2^{k-1}<2^k\),也讓從高位到低位的按位貪心成為了可能。本文接下來將介紹一系列的位運(yùn)算基本技巧,并結(jié)合例題分析位運(yùn)算優(yōu)化的運(yùn)用。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括寶山網(wǎng)站建設(shè)、寶山網(wǎng)站制作、寶山網(wǎng)頁制作以及寶山網(wǎng)絡(luò)營(yíng)銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,寶山網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到寶山省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

位運(yùn)算技巧

位運(yùn)算的基本運(yùn)算符為:&, |, ^, <<, >>, ~,分別表示按位與、或、異或、左移,右移,取反。需要注意的是,由于位運(yùn)算的優(yōu)先級(jí)較低,運(yùn)算時(shí)最好加上括號(hào)。

假設(shè)二進(jìn)制位的最低位為第 \(0\) 位,當(dāng)前的數(shù)為 \(x\),則

  • \(x\) 左移,右移一位:x << 1,x >> 1;
  • \(x\) 最后一位變?yōu)?\(1,0\)x | 1,(x|1) - 1;
  • \(x\) 二進(jìn)制第 \(k\) 位變?yōu)?\(1,0\)x | (1 << k),x (& ~(1 << k));
  • \(x\) 二進(jìn)制后 \(k\) 位變?yōu)?\(1,0\)x | ((1<
  • \(x\) 的第 \(k\) 位:(x >> k) & 1
  • \(\operatorname{lowbit}(x)=x \text & (-x)\)

例題

P4310 絕世好題: 給定一個(gè)長(zhǎng)度為 \(n\) 的數(shù)列 \(a_i\),求 \(a_i\) 的子序列 \(b_i\) 的最長(zhǎng)長(zhǎng)度 \(k\),滿足 \(b_i \& b_{i-1} \ne 0\),其中 \(2\leq i\leq k\),& 表示位運(yùn)算取與。

這道題明顯是一個(gè)有關(guān)序列分割的動(dòng)態(tài)規(guī)劃題目。設(shè) \(f_i\) 表示前 \(i\) 項(xiàng)的最大長(zhǎng)度且 \(i\) 必選,那么 \(f_i=\max_{j。這樣樸素的動(dòng)態(tài)規(guī)劃轉(zhuǎn)移的時(shí)間復(fù)雜度是 \(O(n^2)\),無法通過全部的測(cè)試點(diǎn)。

利用位運(yùn)算,我們可以不要枚舉上一個(gè)位置 \(j\),而是枚舉二進(jìn)制下哪一位與 \(a_i\) 取與后為 \(1\)。

具體地,我們?cè)O(shè) \(g[i,p]\) 表示前 \(i\) 項(xiàng)最終第 \(p\) 位為 \(1\) 的最大長(zhǎng)度。則,我們可以枚舉所有 \(a_i\) 的二進(jìn)制為 \(1\) 的位置,即 \(f_i=\max\{g[i-1,p]\ |\ a_i\text{的第p位為1}\}\)。然后,對(duì)于 \(g[i,p]\),若 \(a_i\) 的第 \(p\) 位為 \(0\),那么 \(g[i,p]\leftarrow g[i-1,p]\),否則 \(g[i,p]\leftarrow \max(g[i-1,p],f_i)\)。

容易發(fā)現(xiàn),\(g_i\) 數(shù)組的取值僅與 \(g_{i-1}\) 有關(guān),因此可以通過滾動(dòng)數(shù)組的方式優(yōu)化空間。總的時(shí)間復(fù)雜度為 \(O(n\log \omega)\),空間復(fù)雜度為 \(O(n+\log \omega)\),其中 \(\omega\) 表示值域。

P4310 代碼
int n, a, f, g[2][31];
/*
f[i] 表示以 i 結(jié)尾的最長(zhǎng)子序列長(zhǎng)度
g[i, p]表示前 i項(xiàng)第p位為1的最大長(zhǎng)度
f[i] = max{g[i-1, p] | a[i]第p位為1} + 1
g[i, p] = 
	max(g[i-1, p], f[i]), a[i]第p位為1
	g[i-1, p], a[i]->p = 0
優(yōu)化:g[i, p]第一維滾動(dòng)
*/
int main () {
	int ans = 0;
	read(n);
	rep(i, 1, n) {
		read(a);
		f = 1;
		rep(p, 0, 30)
			if((a >> p) & 1) 
				f = max(f, g[(i - 1) & 1][p] + 1);
		rep(p, 0, 30)
			if((a >> p) & 1)
				g[i & 1][p] = max(g[(i - 1) & 1][p], f);
			else g[i & 1][p] = g[(i - 1) & 1][p];
		ans = max(ans, f);
	}
	writeln(ans);
	return 0;
}

按位取與: 給定一個(gè)長(zhǎng)度為 \(n\) 的序列 \(a_i\),請(qǐng)你求出 \(\max\{a_i\&a_j\}\),其中 \(1\le i,\(a_i\le 10^{18}\)

本題暴力的復(fù)雜度為 \(O(n^2)\),顯然無法通過。此時(shí),我們需要利用按位貪心的思想。按位貪心是指從高位到低位遍歷,優(yōu)先使得高位為 \(1\),只有高位無法為 \(1\) 時(shí)才使這一位為 \(0\),并繼續(xù)按此法則考慮下一位。其正確性證明如下:

假設(shè)目前考慮最高位為第 \(k\) 位,當(dāng)?shù)?\(k\) 位為 \(1\) 而后 \(k-1\) 位均為 \(0\) 時(shí),收益為 \(2^k\);當(dāng)?shù)?\(k\) 位為 \(0\) 而后 \(k-1\) 位均為 \(1\) 時(shí),收益為 \(2^{k-1}+2^{k-2}+\cdots+2^0\)。利用等比數(shù)列求和公式可得,后者等于 \(2^k-1<2^k\),因此高位為 \(1\) 更優(yōu)。

對(duì)于本題,由于每一位之間的計(jì)算互相獨(dú)立,可以從高到低按位貪心。假設(shè)目前訪問到第 \(p\) 位,如果第 \(p\) 位為 \(1\) 的數(shù)的個(gè)數(shù) \(\ge 2\),那么最終答案里該位為 \(1\)。此時(shí),所有第 \(p\) 位為 \(0\) 的數(shù)都不再參與后續(xù)的計(jì)算。因此,我們可以用兩個(gè)動(dòng)態(tài)數(shù)組 vector 存儲(chǔ)當(dāng)前輪合法的數(shù)和下一輪合法的數(shù),并用滾動(dòng)數(shù)組的方式傳遞;若數(shù)組大小 \(\ge 2\) 則將 \(ans\) 的第 \(p\) 位置為 \(1\)ans |= (1ll<)。

這樣,時(shí)間復(fù)雜度為 \(O(n\log \omega)\),空間復(fù)雜度為 \(O(n)\)。需要注意的是,由于值域達(dá)到 long long 的范圍,而 c++ 中整數(shù)默認(rèn)的類型為 int,左移操作時(shí)需要使用 1ll 而非 1,這也是我在 CSP2020 時(shí)曾經(jīng)犯下的錯(cuò)誤。

部分代碼
ll n, a[maxn], ans, now;
vector  id[2];
int main () {
	read(n);
	rep(i, 1, n) read(a[i]), id[0].push_back(i);
	Rep(p, 30, 0) {
		ll nxt = (now ^ 1);
		id[nxt].clear();
		for(unsigned int i = 0; i < id[now].size(); i++) {
			int u = id[now][i];
			if((1ll << p) & a[u]) 
				id[nxt].push_back(u);
		}
		if(id[nxt].size() < 2) continue;
		ans |= (1ll << p);
		now = nxt;
	}
	writeln(ans);
	return 0;
}

當(dāng)然,你也可以對(duì)本題所求的內(nèi)容進(jìn)行拓展,比如求兩兩 \(\text{and, or, xor}\) 的最大值,并提交到 there。事實(shí)上,異或的最大值本質(zhì)上也是按位貪心,輔以 \(01Trie\);位或的最大值則需要數(shù)位 DP。


當(dāng)前標(biāo)題:位運(yùn)算
文章位置:http://weahome.cn/article/dsoihso.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部