百度之星 2018 复赛 1003. 带劲的 and 和
Accepts: 791 Submissions: 2435
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Problem
Description
度度熊专门研究过 “动态传递闭包问题”,他有一万种让大家爆蛋的方法;但此刻,他只想出一道简简单单的题 —— 至繁,归于至简。
度度熊有一张 n 个点 m 条边的无向图,第 $i$ 个点的点权为 $v_i$。
如果图上存在一条路径使得点 i 可以走到点 j,则称 i,j 是带劲的,记 $f (i,j)=1$;否则 $f (i,j)=0$。显然有 $f (i,j) = f (j,i)$。
度度熊想知道求出:$\sum ^{n-1}{i=1} \sum^{n}{j=i+1} f(i, j) \times \max(v_i, v_j) \times (v_i & v_j)$
其中 $&$ 是 C++ 中的 and 位运算符,如 $1 & {3}=1, 2 & 3=2$。
请将答案对 $10^9+7$ 取模后输出。
Input
第一行一个数,表示数据组数 TT。
每组数据第一行两个整数 n,m;第二行 n 个数表示 $v_i$;接下来 mm 行,每行两个数 u,v,表示点 u 和点 v 之间有一条无向边。可能有重边或自环。
数据组数 T=50,满足:
- $1 \le n,m \le 100000$
- $1 \le v_i \le 10^9$
其中 90% 的数据满足 $n,m \le 1000$
Output
每组数据输出一行,每行仅包含一个数,表示带劲的 and 和。
Sample Input
1 | 1 |
Sample Output
1 | 99 |
Solution
先放下官方题解吧
比较简单的数据结构题,需要掌握位运算每一位是独立的性质,难度 3 分。
因为是无向图,所以有 f (i,j) = f (j,i) f (i,j)=f (j,i),不妨用并查集得到图上各个连通块,连通块中每对点的 ff 均为 1,而不同连通块的点对互不影响。
求和的式子中有 $\max$ 一项,不妨对于每个联通块中的点,将它们的权值 vv 从小到大排序,这样枚举到一个点,计算它和前面点之间的贡献时,$\max$ 就是当前点的权值。
还需要处理 && 运算符,这是一个经典的套路,只需要对于二进制的每一位统计出有多少个点在这一位上是 1,对于每一位分开计算贡献即可。举个例子,如果要计算权值 11 和权值 7 的贡献,则有
$max(7,11) \times (7 & 11) = 11 \times ((1 + 2 + 4) & (1 + 2 + 8)) = 11 \times 1 + 11 \times 2$
复杂度为 $O (n \log n + n \times 30)$,因为二进制位有 30 个。
并查集和排序自己想到了,但按位的操作自己没有见过,这次也算是见识到了。
用一个 dp 数组记录下比它小的数字该位有多少个 1 就吼惹。
AC 代码
1 |
|