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

JR_飘摇
这个家伙确实很懒,但至少知道他会爆0搬运于
2025-08-24 22:07:33,当前版本为作者最后更新于2018-12-27 15:42:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题解放这里吧!
当然也在my blog里放了一份
吐槽ing:一道有趣的二进制题.
注意加粗部分是限制条件我们先考虑暴力分分:
首先那个值一看就知道是二进制。
对于这个暴力分,应该是一种很暴力(
废话)的解法,我们直接从向枚举,然后判断这一个数合不合法,如果合法,就+1,直到找到第大,输出答案即可。考虑
这里我们就要开始讨论二进制算法了。
首先我们考虑巨佬站队方式的限制,对于每个询问,假设巨佬的值是,若,那区间就没有作用了,我们的查询区间就直接缩成了,这一个限制条件就解决了。
我们再考虑巨佬的站队对蒟蒻的约束作用(
即限制了某些位必须是0):首先我们假设没有这个条件,很显然的,如果第大的站队方式的值是,那么第大的站队方式的值就是(二进制转十进制),
接着我们再考虑存在某些位必须是的情况:
这里的方法是把所有有约束条件的删去,得到一个新的,没有约束条件的数。
比如这里有一个第大的数的二进制数,其中所有都是被限制了的
1 0 1 0 1 0我们把所有被限制的0删去,得到一个没有被限制的数:
1 1 1显然这个值是7,求第大的数时,我们将7-1,得到6.
1 1 0然后,我们再把刚才去掉的0加回去
1 0 1 0 0 0这就是我们要找的数。
关于删除操作,我是这样做的,假设我们要删除下面这个二进制的第3个数:
1 1 1 1 1 1 ^我们先把后2位取下来:
1 1 1 1 0 0 s = 1 1再删除第3位:
1 1 1 0 0 0整体右移一位,在把搬回去。
插入也是同理(改成左移)
具体代码实现(时间复杂度):
void del(LL c) { LL o = c - 1; s = ((((s & (~ c)) & (~ o)) >> 1) ^ (s & o)); } void insert(LL c) { LL o = c - 1; x = (((x & (~ o)) << 1) ^ (x & o)); }然后还有一个问题就是,我们首先要找到满足的最大值(知道了以后就可以解题了)。
我们同样先不考虑后面的限制,我们把和列出来从高位到低位枚举,假设蒟蒻的站队方式最大值为,如果我们枚举到一位,满足这一位是1,也是1,由于约束,则蒟蒻的站队在这一位上必须是0,由于是从高位往低位枚举,则高位上肯定没有这种情况(否则就不会出现在这里了),那在这位上肯定是0,这时,可以发现,无论后面取什么数,其结果都比小!那我们的值就可以取到这位是0,后面都是1的情况。
对于其他情况,不难发现,我们必须要取所在的值才能保证最大。
最后,找到了后,我们去除限制条件,把所有巨佬所在值为1的权位上的值改为0,我们就找到了最大值。
代码也不长(甚至连数组都不用开),但是如果没思路的话,代码不一定看得懂:
#include<cstdio> #include<iostream> #define LL unsigned long long using namespace std; LL n,m,t,q; LL p,a,b,k,s,x; void del(LL c) { LL o = c - 1; s = ((((s & (~ c)) & (~ o)) >> 1ll) ^ (s & o)); } void getmax() { LL j = (1ll << (n - 1)); for( ;j ; (j >>= 1)) if((b & j) && (p & j)) break; if(!j) k = b; else k = ((b & (~ j)) | (j - 1)); j = (1ll << (n - 1)); for(; j; (j >>= 1)) if(p & j) k = (k & (~ j)); j = (1ll << (n - 1));s = k; for(; j; (j >>= 1)) if((k & (~ (j - 1))) && (p & j)) del(j); } void insert(LL c) { LL o = c - 1; x = (((x & (~ o)) << 1ll) ^ (x & o)); } int main() { scanf("%lld%lld", &n,&m); for(LL i = 0;i<n;++i) { scanf("%lld", &t); p |= (t << i); } while(m --) { scanf("%lld%lld%lld",&a,&b,&q); b = min(p-1, b); getmax(); x = s - q + 1; for(LL j = 1;j <= (1ll << n);j <<= 1) if(p & j) insert(j); if(x < a|| x>p) printf("POOR AFO!\n"); else printf("%lld\n", x % 20031102); } }
- 1
信息
- ID
- 4006
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者