一年补一题,一题补一年(1)| [省选联考 2024] 迷宫守卫
MatrixGroup · · 个人记录
题目链接
求出答案序列的第一个数是容易的。设
考虑模拟求答案的过程。考虑设计
首先,如果子树内要走的第一个点在右子树,那显然两边都至少要用
否则,设右子树要用
直接模拟,复杂度
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0,del##i##verme=int(n);i<del##i##verme;++i)
#define rep1(i,n) for(int i=1,parano##i##a=int(n);i<=parano##i##a;++i)
#define per(i,n) for(int i=int(n)-1;i>=0;--i)
#define per1(i,n) for(int i=int(n);i>=1;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define y0 LingLuo
#define y1 VividCycle
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using namespace std;
const ll mod1=998244353;
const ll mod2=1000000007;
unsigned time_related_rand()
{
return unsigned(std::chrono::steady_clock::now().time_since_epoch().count());
}
const ll INF=0x3f3f3f3f3f3f3f3fll;
int t,n;
int q[131072];
ll w[131072];
vector<int> val[131072];
vector<ll> dp[131072];
void solve(int ver)
{
if(ver>=(1<<n))
{
val[ver].pb(q[ver]);val[ver].pb(20120712);
dp[ver].pb(0);dp[ver].pb(INF);
}
else
{
int L=ver<<1,R=ver<<1|1;
solve(L);solve(R);
int s=int(val[L].size())-1;
int l=0,r=0;
while(l!=s||r!=s)
{
if(val[L][l]<val[R][r])
{
val[ver].pb(val[L][l]);
dp[ver].pb(min(INF,min(w[ver],dp[R][r])+dp[L][l]));
++l;
}
else
{
val[ver].pb(val[R][r]);
dp[ver].pb(min(INF,min(w[ver],dp[R][r])+dp[L][l]));
++r;
}
}
val[ver].pb(20120712);
dp[ver].pb(INF);
}
}
vector<int> answer;
ll dfs(int ver,ll rem)
{
if(ver>=(1<<n))
{
answer.pb(q[ver]);return rem;
}
int L=ver<<1,R=ver<<1|1;
int target=*(upper_bound(dp[ver].begin(),dp[ver].end(),rem)-1-dp[ver].begin()+val[ver].begin());
ll vl=*(upper_bound(val[L].begin(),val[L].end(),target)-val[L].begin()+dp[L].begin()),
vr=*(upper_bound(val[R].begin(),val[R].end(),target)-val[R].begin()+dp[R].begin());
if(binary_search(val[L].begin(),val[L].end(),target))
{
ll vval=dfs(L,rem-min(w[ver],vr));
if(vval+min(w[ver],vr)>=vr) return dfs(R,vval+min(w[ver],vr));
return dfs(R,vval);
}
return dfs(L,dfs(R,rem-vl)+vl);
}
ll s;
void Q()
{
cin>>n>>s;
rep1(i,(1<<n)-1) cin>>w[i];
rep1(i,(1<<n)) cin>>q[i+(1<<n)-1];
rep1(i,(2<<n)-1)
{
val[i].clear();dp[i].clear();
}
solve(1);
answer.clear();
dfs(1,s);
for(int x:answer) cout<<x<<" ";
cout<<'\n';
}
int main()
{
ios_base::sync_with_stdio(false);cin.tie(0);cin>>t;while(t--)Q();
return 0;
}
/* things to check
1. int overflow or long long memory need
2. recursion/array/binary search/dp/loop bounds
3. precision
4. special cases(n=1,bounds)
5. delete debug statements
6. initialize(especially multi-tests)
7. = or == , n or m ,++ or -- , i or j , > or >= , < or <=
8. keep it simple and stupid
9. do not delete, use // instead
10. operator priority
11. is there anything extra to output?
12. ...
*/
/* something to think about
1. greedy? dp? searching? dp with matrix/ segment tree? binary search?
2. If contains "not", why not ?????? or few affect?
*/