【题解】智力检测

· · 题解

感谢出题人 Tian36309 写下了此篇题解的初版,并对修改版提出了宝贵的修改意见。

[IAMOI R1] 智力检测 题解

定义 I 定义“用 va_u”代表对 u_i=uv_i=v 进行题目所述的操作

定义 II 定义“a_u 被取”表示对于某个 v,用 v 取了 a_u

命题 I 取数时,a_u 不可能被重复取。

命题 II 如果 x < 2^{k-1} 或者 x \ge 2^k,那么本次询问无解。

以下的分析令 x \gets x - 2^{k-1}(这一位二进制数不用取,因此不考虑)

命题 III 可以通过若干次操作使 a_k = x,当且仅当如果 x 二进制下不包含连续奇数个 1

那么我们就有了第一个思路:

命题 IV 对于每一个合法的答案(即不出现连续奇数个 1,后同),其一定是 3 的倍数。

证明平凡,因为相邻两个 1 可以理解为 x+2x,而这个数很明显是 3 的倍数。

命题 V 对于每一个合法的答案,用它除以 3 后进行二进制拆分,一定不会出现连续的 1

命题 VI 符合是 3 的倍数和除以 3 后进行二进制拆分,不会出现连续的 1 的数必然是合法的答案。

那么,我们只需要判断如下两个条件即可:

对于第二个条件,可以通过 \lfloor\dfrac{x}{3}\rfloor 按位与 \lfloor\dfrac{2x}{3}\rfloor 来判断。显然如果没有连续的 1,上述式子的结果是 0

时间复杂度 O(T)

#include<bits/stdc++.h>
using namespace std;
long long T,k,sum,mi[100];
inline long long read()
{
    char c=getchar();long long x=0,f=1;
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=x*10+c-48;
    return x*f;
}
int main(){
    T = read();
    mi[1] = 1;
    for(int i=2;i<=62;i++)mi[i] = mi[i-1]*2;
    while(T--){
        k = read();
        sum = read();
        if(sum >= mi[k+1] or sum < mi[k]){
            printf("0");
            continue;
        }
        sum -= mi[k];
        if(sum % 3 == 0 and (((sum/3) & (sum/3*2)) == 0))printf("1");
        else printf("0");
    }
    return 0;
}