1 条题解
-
0
自动搬运
来自洛谷,原作者为

liangbob
我们生活在大地上,但我们的梦想超越天空。搬运于
2025-08-24 23:10:02,当前版本为作者最后更新于2024-11-23 10:35:44,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
感谢出题人 Tian36309 写下了此篇题解的初版,并对修改版提出了宝贵的修改意见。
[IAMOI R1] 智力检测 题解
定义 I 定义“用 取 ”代表对 , 进行题目所述的操作
定义 II 定义“ 被取”表示对于某个 ,用 取了
命题 I 取数时, 不可能被重复取。
- 证明显然,反证法。考虑到如果取重复的 会取到 ,你后面无论怎么取,都无法取回一个非负数。同时题目保证 是个非负数,矛盾,所以不能重复取。
命题 II 如果 或者 ,那么本次询问无解。
-
根据命题 I,可以知道 不能重复取,这意味着每个操作的 和 均非负,也就是说,经过多次操作之后, 必然只增不减,那么 自然也就无解了。
-
继续根据命题 I,可以继续知道 不能重复取,注意到最极限的情况显然是通过反复操作把 ,,,……, 取一次,也就是说 ,这显然不到 ,于是 无解。
以下的分析令 。(这一位二进制数不用取,因此不考虑)
命题 III 可以通过若干次操作使 ,当且仅当如果 二进制下不包含连续奇数个 。
-
由于 数组的特殊性质,我们把 数组转换成二进制后发现,第一次取 和 就相当于把 的第 位和第 位改为 ,而下一次操作中选的数如果是 则这次操作后那一个数的第 位都将变为 。
-
由于 ,因此上述性质成立。
-
由于每次操作都是将两位改为 ,因此如果 二进制下包含连续奇数个 ,那么必然无法操作得到。
那么我们就有了第一个思路:
-
对于每一次询问,将 进行二进制拆分,如果发现存在连续奇数个 输出 ,否则输出 。
-
单次询问 ,常数比较好的话可以获得 分。(卡一卡没准可以拿满分)
命题 IV 对于每一个合法的答案(即不出现连续奇数个 ,后同),其一定是 的倍数。
证明平凡,因为相邻两个 可以理解为 ,而这个数很明显是 的倍数。
命题 V 对于每一个合法的答案,用它除以 后进行二进制拆分,一定不会出现连续的 。
- 观察到,除以 相当于在除以 ,试一下就会发现,二进制下连续偶数个 除以 就等于 。
- 而若一个不包含连续 的二进制数乘 ,结果中一定只包含连续的偶数个 (相当于将其右移一位再相加)。
- 综上,得证。
命题 VI 符合是 的倍数和除以 后进行二进制拆分,不会出现连续的 的数必然是合法的答案。
- 显然,所有不含连续的 的二进制数乘三都是合法答案。
那么,我们只需要判断如下两个条件即可:
- 是 的倍数
- 除以 后二进制下不含有连续的 。
对于第二个条件,可以通过 按位与 来判断。显然如果没有连续的 ,上述式子的结果是 。
时间复杂度 。
#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; }
- 1
信息
- ID
- 10792
- 时间
- 500ms
- 内存
- 128MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者