多亏了橘子猫的博客,让我明白了,橘子猫NB,这里贴一手他的博客链接
https://blog.csdn.net/ccsu_cat/article/details/100076916
题目链接:https://codeforces.com/contest/1208/problem/F
题意:给你 n 个数,求 max ( a i ∣ ( a j & a k ) ) \max( a_{i}| (a_{j}\&a_{k})) max(ai∣(aj&ak)),i 思路:很容易想到枚举 i ,然后贪心,再然后就不知道该怎么写… 从后往前枚举 i ,然后对 a i a_{i} ai 没有的高位有1加1,然后从这个1的集合一直贪下去。这样子就需要维护一个个集合,集合 S ( m ) S(m) S(m) 代表满足 a j ∈ m a_{j}\in m aj∈m 的数量,如果这个集合数量>=2,则 a i a_{i} ai 肯定顺着 集合 S 走下去。 举个例子: 看了上面的过程,很容易一个ai 做的贡献就是给所有ai的子集+1,这就很容易想到枚举子集的操作了。 但是由于题目数据太大,肯定会超时,所以必要要优化。很明显,题目数据 ai<=2e6,并且我们dp[i]只需要取值为0,1或者>=2就行了,所以状态数<=6e6,然而具体怎么实现呢。
4
2 8 4 7
4…for(int i=S;i;i=(i-1)&S)
dp[i]++;
举个例子, 设 i n t int int S , i S,i S,i,并且 i & S = i , < = = > i ∈ S ( 就 是 i 是 S 的 儿 子 ) i\&S=i,<==> i \in S(就是i是S的儿子) i&S=i,<==>i∈S(就是i是S的儿子),如果dp[i]>=2,但是我们当前在更新S,还需不需要继续往下更新 i 呢,仔细思考发现是没必要的。然后该怎么枚举呢。
很容易想到一个方法,枚举需要修改的低位1,画个图表示一下。然后可以直接递归下去。
然后没啥好BB的,具体方式怎么写都行,就是防止一个点和他的儿子被一直加下去。#include