正向模拟一遍,得出X数组必须单调不减且值大于等于下标。
当X[i]==X[i+1]时,B[i]可以构造为A[i+1]+t,否则B[i]为A[i+1]+t-1,即恰不能被后一项所使用。
最后需要检验B数组单调增,以及AB可以正向求解出X。
ll A[M],B[M],t;
int X[M],n;
int solve()
{
for(int i=1;i<=n;++i)
if(X[i]1] || X[i]return 0;
for(int i=1;i1] + t - !(X[i]==X[i+1]);
B[n] = A[n] + t + 1;
for(int i = n, lst = n; i; --i)
{
if(lst != X[i] || B[i] <= B[i-1]) return 0;
if(B[i-1]-A[i]1;
}
return 1;
}
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
n = read(), t = read();
for(int i=1;i<=n;i++) A[i] = read();
for(int i=1;i<=n;i++) X[i] = read();
if(solve())
{
printf("Yes\n");
for(int i=1;i<=n;i++)
printf("%I64d ",B[i] );
}
else
printf("No\n");
return 0;
}
要抓住数轴上一个会移动的点,每次选择一段区间查询,可以知道点是否在这个区间内,当区间长度为1且点在区间内,抓捕成功。数轴长度1e18,点移动速度10,最多查询4500次。
在保证点在[l,r]范围内时,先查询[l-10,m+10],如果不在,再查询[m,r+20],就可以将长度为n的区间缩小到长度为n/2+20的区间,当区间长度缩小到一个设定值(如80)以内时,随机选取区间[l,r]内一个点尝试抓捕,如果失败,则仍保证点在[l-10,r+10]内,继续重复即可。
最多4次查询内就会有一次抓捕,每次概率是1/80,1000次查询不到的概率0.0000001。
const int RANGE = 80;
ll n;
ll suc_l, suc_r; //确信范围
bool query(ll a,ll b)
{
char sta[5];
write(a);putchar(' ');write(b);putchar('\n');
fflush(stdout);
scanf("%s",sta);
if(sta[0]=='B') exit(0);
return sta[0]=='Y'?1:0;
}
void narrow()
{
bool test = 0;
while(suc_r - suc_l >= RANGE)
{
ll l, r, m = (suc_l + suc_r)/2;
if(test)
{
l = max(1LL, m);
r = min(n, suc_r + 20);
}
else
{
l = max(1LL, suc_l - 10);
r = min(n, m + 10);
}
if(query(l,r))
{
suc_l = l;
suc_r = r;
test = 0;
}
else
{
test = 1;
}
}
}
bool seek()
{
suc_l = max(1LL, suc_l - 10), suc_r = min(n, suc_r + 10);
ll p = suc_l + (ll)rand() % (suc_r-suc_l+1);
return query(p,p);
}
int main(void)
{
n = read();read();
suc_l = 1, suc_r = n;
srand(time(0));
for(narrow();!seek();narrow());
return 0;
}
对于构造题:
构造题如果没有明显的思路时,可以想想正向求解,然后反向构造。
构造完之后,最好进行一次检验观察结果是否正确。
求[L,R]区间随机数:L + rand()%(R-L+1) 注意rand()最大只有32767