CF939 D

superl61發表於2024-04-13

CF939 D

  • 讓你把區間分成 \(k\) 段, 段內用 \(xor\) 連線, 段之間用 \(or\) 連線,問你在結果不大於 \(x\) 的前提下, \(k\) 的最大值
  • \(1 \leq n \leq 10^5, 0 \leq x,a_i \leq 2^30\)
  • 標籤:正向思維,二進位制操作,按位貪心(從高到低)
  • 參考題解1參考題解2
  • 註釋版code
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
using namespace std;
using ll=long long;
const int N=1e5+5;
int t,n,x,ans=-1;
inline void sol(vector<int> a,const int p=30){// now deal with dep p
	if(p<0) return ans=max(ans,(int)a.size()),void();
	vector<int> pos;//pos: the set of the positione of all element that is 1 in pth bit
	//Attention: pos take account for postion, rather than the concrete element
	F(i,0,(int)a.size()-1){
		if((a[i]>>p)&1) pos.emplace_back(i);	
	}
	//odd
	if(pos.size()%2==1 && ((x>>p)&1)==0) return;
	//the pth of x is 0 => fail?
	if(pos.size()%2==1 && ((x>>p)&1)==1) return sol(a,p-1);
	//the pth of x is 1 => continue to solve
	//even
	bool rmv[(int)a.size()];
	vector<int> b,c=a;//copy a to c
	memset(rmv,0,sizeof(rmv));
	//create the new seq
	for(int i=0;i<(int)pos.size();i+=2){//every postion with 1
		for(int j=pos[i]+1;j<=pos[i+1];++j){
			rmv[j]=1; c[pos[i]]^=c[j];
		}
	}
	F(i,0,(int)a.size()-1){
		if(!rmv[i]) b.emplace_back(c[i]);
	}
	
	//make decision
	if(((x>>p)&1)==0) return sol(b,p-1);//注意是return.兩種情況選其一,單次複雜度就是 O(N)
	ans=max(ans,(int)b.size());
	//如果x上的這一位是1,第一,若按b這種分法,那麼已經最優了
	return sol(a,p-1);
		//第二,那麼其實這一位的限制沒有任何意義,仍然踩在a的基礎上,直接去考慮下一位.
}
//核心:倒著做,簡單來說對於每一次操作,奇數個1就直接考慮最終結果,
 //偶數個1就按最優策略(相鄰兩兩配對)新增xor,這樣能使這一位上的異或和最終一定為0(儘可能小),剩下沒確定符號的位置在solve(b,p-1)中繼續討論
 //發現了嗎,沒有討論or新增的過程,或者換句話說or的新增過程是依靠貪心來約束的.
 //b.size()即段數,不一定最優
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>t; while(t--){
		cin>>n>>x;
		vector<int> a(n);
		F(i,0,n-1) cin>>a[i];
		ans=-1;
		sol(a);
		cout<<ans<<'\n';
	}
	return 0;
}

  • 反思:
    • 經典的二進位制貪心,從低位到高位。核心在以貪心的方式把 \(or\) 運算給迴避掉了,這樣就這剩下一種運算需要處理。
    • 另一方面就是直白的正向思維(感覺有點兒反套路化逆向思維的感覺),就逐漸逐漸加符號上去,而不是先全填成 \(or\) 或者 \(xor\) 再去改。想多了的話反而容易遭。
    • 二進位制貪心不一定是什麼一個字首相同然後0,1之間討論大小關係, 但共同點是兩種貪心都和勢能很像:只關注已有的條件來推測最終的結果,中間具體狀態不關心。

相關文章