首先有個很顯然的 \(\mathcal O(nk^2)\) 的做法,即二分答案,然後 trie 樹上判斷。
對於 trie 樹上一顆子樹內的判定,考慮當前二分的 \(\text{mid}\) 這一位是 \(1\) 還是 \(0\) 以及 \(x\) 這一位填什麼。
-
對於 \(1\) 的情況,如果填 \(0\),那麼右兒子仍然合法,左兒子中的數必須要放到集合 \(S\) 中。預處理出一個子樹內 \(a\) 的最小值以及 \(b\) 的和,遞迴到右兒子繼續求解。填 \(1\) 的情況類似。
-
對於 \(0\) 的情況,如果填 \(0\),那麼右兒子已經滿足異或值 \(>\text{mid}\),遞迴到左兒子繼續求解。填 \(1\) 的情況類似。
發現這種做法每個點只會被遍歷一次,可以獲得雲鬥 \(92\) & CCF \(72\) 分的好成績。
最佳化的部分就簡單了。
考慮怎麼最佳化。發現可以把二分去掉,在子樹內貪心考慮如果答案的當前位填 \(1\),剩下的位全填 \(0\) 是否有解,如果有解就填 \(1\),否則填 \(0\)。
發現判定可以用之前預處理出來的東西 \(\mathcal O(1)\) 做,每個點只會被遍歷一次。所以時間複雜度 \(\mathcal O(nk)\),可以透過此題。
參考程式碼:
#include<bits/stdc++.h>
#define mxn 100003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
inline __int128 read1(){
__int128 x=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
inline void print(__int128 a){
if(a>9)print(a/10);
putchar(a%10+'0');
}
int c,T,n,m,k,b,sm,tot,f[mxn*120],t[mxn*120][2];
__int128 a,mn,pw[123],A[mxn],s[mxn*120];
void ins(){
int p=0;
drep(i,k-1,0){
if(!t[p][(a>>i)&1])t[p][(a>>i)&1]=++tot,f[tot]=0,s[tot]=a;
p=t[p][(a>>i)&1],f[p]=min(f[p]+b,m+1),s[p]=min(s[p],a);
}
}
__int128 solve(__int128 mid,int x,int d,__int128 now,__int128 mn,int sum,bool fl){
if(sum>m)return 0;
if(d<0)return mid;
__int128 ans=0;
if(pw[d]-1+(fl&&t[x][1]?min(mn,s[t[x][1]]):mn)+now>=mid){
ans=max(ans,solve(mid+pw[d],fl?t[x][0]:0,d-1,now+pw[d],fl&&t[x][1]?min(mn,s[t[x][1]]):mn,min(sum+(fl?f[t[x][1]]:0),m+1),fl&&t[x][0]));
}
if(pw[d]-1+(fl&&t[x][0]?min(mn,s[t[x][0]]):mn)+now>=mid+pw[d]){
ans=max(ans,solve(mid+pw[d],fl?t[x][1]:0,d-1,now,fl&&t[x][0]?min(mn,s[t[x][0]]):mn,min(sum+(fl?f[t[x][0]]:0),m+1),fl&&t[x][1]));
}
if(ans)return ans;
if(pw[d]-1+mn+now>=mid){
ans=max(ans,solve(mid,fl?t[x][0]:0,d-1,now,mn,sum,fl&&t[x][0]));
}
if(pw[d+1]-1+mn+now>=mid){
ans=max(ans,solve(mid,fl?t[x][1]:0,d-1,now+pw[d],mn,sum,fl&&t[x][1]));
}
return ans;
}
signed main(){
c=read(),T=read();
pw[0]=1;
rep(i,1,120)pw[i]=pw[i-1]*2;
while(T--){
n=read(),m=read(),k=read();
rep(i,0,tot)t[i][0]=t[i][1]=0;
tot=0;
sm=0,mn=pw[k];
rep(i,1,n)A[i]=read1();
rep(i,1,n){
b=read(),a=A[i];
ins();
sm=min(sm+b,m+1),mn=min(mn,a);
}
if(sm<=m){
print(mn+pw[k]-1);
puts("");
continue;
}
print(solve(0,0,k-1,0,pw[k],0,1));
puts("");
}
return 0;
}