【紫喬圖鑑】WUXXX 橋公 [手殺] [身份]
阿新 • • 發佈:2022-04-05
本題是一道數學題。
我們首先需要交換一下求和符號,然後利用二進位制的性質拆式子即可。
具體過程如下:
\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}(x_i \text{ and }x_j) \times (x_j \text{ or } x_k)\)
\(=\sum\limits_{j=1}^{n}\sum\limits_{i=1}^{n}\sum\limits_{k=1}^{n}(x_i \text{ and }x_j) \times (x_j \text{ or } x_k)\)
\(=\sum\limits_{j=1}^{n}\sum\limits_{i=1}^{n}(x_i \text{ and } x_j) \times \sum\limits_{k=1}^{n}(x_j \text{ or } x_k)\)
\(=\sum\limits_{j=1}^{n}(\sum\limits_{i=1}^{n}(x_i \text{ and } x_j) \times \sum\limits_{k=1}^{n}(x_j \text{ or } x_k))\)
於是我們只需要按二進位制位拆分,然後處理即可。
程式碼:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN = 5e5 + 10, P = 1e9 + 7; int t, n; LL x[MAXN], ans, sum[MAXN]; LL read() { LL sum = 0, fh = 1; char ch = getchar(); while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar();} while (ch >= '0' && ch <= '9') {sum = (sum << 3) + (sum << 1) + (ch ^ 48); ch = getchar();} return sum * fh; } int main() { t = read(); while (t--) { n = read(); ans = 0; for (int i = 1; i <= n; ++i) x[i] = read(); memset(sum, 0, sizeof(sum)); for (int i = 1; i <= n; ++i) for (int j = 0; j < 60; ++j) if (1ll << j & x[i]) sum[j]++; for (int i = 1; i <= n; ++i) { LL sum1 = 0, sum2 = 0; for (int j = 0; j < 60; ++j) { LL tmp = (1ll << j) % P; if (1ll << j & x[i]) sum1 = (sum1 + sum[j] * tmp % P) % P, sum2 = (sum2 + n * tmp) % P; else sum2 = (sum2 + sum[j] * tmp) % P; } ans = (ans + sum1 * sum2 % P) % P; } printf("%lld\n", ans); } return 0; }