1. 程式人生 > 其它 >leetcode 1300. 轉變陣列後最接近目標值的陣列和

leetcode 1300. 轉變陣列後最接近目標值的陣列和

在補NOIonline
先隨手做一下這個T2的弱化版。
感覺這個就是T2的trick
\(tire\)樹認知不夠,數位思想差啊。

考慮用\(tire\)樹維護數集,然後高位往低位處理\(l\),如果\(l_i\)\(1\),則和\(p_i\)相同一側子樹可以全部加入答案,再走和\(p_i\)不同一側遞迴下去,若\(l_i\)為0,則必須走\(p_i\)同側。

CF817E Choosing The Commander
#include<iostream>
#include<cstdio>
#define ll long long
#define N 100005

ll n;
int cnt;
int ch[N * 16][2],s[N * 16];

inline void insert(ll c){
	ll u = 0;
	for(int i = 30;i >= 0;--i){
		if(!ch[u][(c >> i) & 1])
		ch[u][(c >> i) & 1] = ++ cnt;
		s[u] ++ ;
		u = ch[u][(c >> i) & 1];
//		std::cout<<u<<" ";
	}
	s[u] ++ ;
//	puts("");
}

inline void del(ll c){
	ll u = 0;
	for(int i = 30;i >= 0;--i){
		s[u] -- ;
		u = ch[u][(c >> i) & 1];
	}
	s[u] -- ;
}

ll pi,li,ans;

inline void solve(ll u,ll dep){
	if(dep == 0)
	return;
	if((li >> (dep - 1)) & 1){
		ll x = (pi >> (dep - 1) & 1);
//		std::cout<<u<<" "<<1<<" "<<dep - 1<<" "<<x<<" "<<s[ch[u][x]]<<std::endl;
		if(ch[u][x])
		ans += s[ch[u][x]];
		if(ch[u][!x])
		solve(ch[u][!x],dep - 1);
	}
	else{		
		ll x = (pi >> (dep - 1) & 1);
//		std::cout<<u<<" "<<0<<" "<<dep - 1<<" "<<x<<std::endl;		
		if(ch[u][x])
		solve(ch[u][x],dep - 1);
	}	
}

int main(){
	scanf("%lld",&n);
	while(n -- ){
		ll opt;
		scanf("%lld",&opt);
		if(opt == 1){
			ll p;
			scanf("%lld",&p);
			insert(p);
		}
		if(opt == 2){
			ll p;
			scanf("%lld",&p);
			del(p);
		}
		if(opt == 3){
			scanf("%lld%lld",&pi,&li);
			ans = 0;
			solve(0,31);
			std::cout<<ans<<std::endl;
		}
	} 
}

ps:最近程式碼能力提上了,不過還要注意對拍。
以及我還是沒搞懂\(tire\)要開多大空間,從這題上看,得開到\(16n\)(n字串數量)啊。
下回弄懂了,回來補坑。