洛谷P8168
这是一个构造题
如果熟悉二分查找的话,我们可以注意到我们总是先搜索中点,再搜索左右区间:
既然这样,那我们优先考虑把字符串中值为 true 的数字按照从小到大的顺序放在区间中点这样子,我们就可以保证这些数字二分查找的结果一定是正确的。
代码如下
vector<ll> ton;// 用桶装 true 的项
stack<ll> ton2;// 用桶装 false 的项
ton.push_back(-1);
vector<ll> ans(n+1,-1);
for(int i=1;i<=n;i++)
{
if(s[i]=='1')
ton.push_back(i);
else
ton2.push(i);
}
// 把字符串中值为 true 的数字按照从小到大的顺序放在区间中点
auto build=[&](auto self,ll l,ll r,ll ton_l,ll ton_r)->void{
if(ton_l>ton_r) return;
ll mid=(l+r)>>1;
if(ton_l==ton_r)
{
ans[mid]=ton[ton_l];
return;
}
ll ton_mid=(ton_l+ton_r)>>1;
ans[mid]=ton[ton_mid];
self(self,l,mid-1,ton_l,ton_mid-1);
self(self,mid+1,r,ton_mid+1,ton_r);
};
build(build,1,n,1,ton.size()-1);
之后我们考虑处理字符串中值为 false 的数字。题目中要求
完整代码如下
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define IOS ios::sync_with_stdio(0),cin.tie(0)
typedef long long ll;
typedef pair<ll,ll> p;
const int N=2e5+5;
int main()
{
IOS;
ll t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
string s;
cin>>s;
s=' '+s;
vector<ll> ton;// 用桶装 true 的项
stack<ll> ton2;// 用桶装 false 的项
ton.push_back(-1);
vector<ll> ans(n+1,-1);
for(int i=1;i<=n;i++)
{
if(s[i]=='1')
ton.push_back(i);
else
ton2.push(i);
}
// 把字符串中值为 true 的数字按照从小到大的顺序放在区间中点
auto build=[&](auto self,ll l,ll r,ll ton_l,ll ton_r)->void{
if(ton_l>ton_r) return;
ll mid=(l+r)>>1;
if(ton_l==ton_r)
{
ans[mid]=ton[ton_l];
return;
}
ll ton_mid=(ton_l+ton_r)>>1;
ans[mid]=ton[ton_mid];
self(self,l,mid-1,ton_l,ton_mid-1);
self(self,mid+1,r,ton_mid+1,ton_r);
};
build(build,1,n,1,ton.size()-1);
for(int i=1;i<=n;i++)
{
if(ans[i]==-1)
{
ans[i]=ton2.top();
ton2.pop();
}
}
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<(i==n?'\n':' ');
}
}
}