【补题】Codeforces #507(Div1) AB

版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/82527441

1039A. Timetable 构造题

正向模拟一遍,得出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]<X[i-1] || X[i]<i)
            return 0;
    for(int i=1;i<n;++i)
        B[i] = A[i+1] + 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]<t) lst = 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;
}

1039B. Subway Pursuit 交互题,二分,随机

要抓住数轴上一个会移动的点,每次选择一段区间查询,可以知道点是否在这个区间内,当区间长度为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

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/82527441