UPC9575 鑫鑫的算术
题目描述
AK掉五校联考的题目后,鑫鑫在研究二进制在数论中的应用。
鑫鑫给了你n个数,每次你可以从这其中选择两个数a和b,将它们的值分别赋为a and b和a or b(均为二进制位运算)。这样的操作,你可以执行任意多次。鑫鑫希望最终这些数的平方和尽量的大,你能帮他求出这个最大值吗?
鑫鑫给了你n个数,每次你可以从这其中选择两个数a和b,将它们的值分别赋为a and b和a or b(均为二进制位运算)。这样的操作,你可以执行任意多次。鑫鑫希望最终这些数的平方和尽量的大,你能帮他求出这个最大值吗?
输入
第一行一个正整数n,表示数的数量。
第二行n个非负整数,表示鑫鑫给你的n个数。(2≤n≤100000,0≤ai≤108)
第二行n个非负整数,表示鑫鑫给你的n个数。(2≤n≤100000,0≤ai≤108)
输出
一行一个非负整数,表示答案。由于答案太大,你只需要输出答案对998244353(=7×17×223+1,一个质数)取模后的结果。
样例输入
5
1 2 3 4 5
样例输出
99
此类可以操作无限次的题目,一般均与具体的操作执行过程无关,在操作足够次后,会达到一种最优的稳定状态。
在此题中,可以发现,a和b在做题中所给操作前后其二进制各位上1的数目不变,(a、b 和 a&b、a|b 各二进制位上的一的数目相同)。所以题中所给的操作本质上是将一个数某二进制位上的1换到另一个数上。所以我们
可以直接求出所有二进制位上1的数目,然后直接构造组成最大结果的数。
#include "bits/stdc++.h" using namespace std; typedef long long ll; int bit[50]; const int mod = 998244353; int main() { //freopen("input.txt", "r", stdin); int n; scanf("%d", &n); ll temp; for (int i = 1; i <= n; i++) { scanf("%lld", &temp); for (int j = 0; j < 31; j++) { if (temp & (1 << j)) { bit[j]++; } } } ll ans = 0; while (n--) { temp = 0; for (int i = 0; i < 31; i++) { if (bit[i] > 0) { temp += (1 << i); bit[i]--; } } ans = (ans + temp * temp) % mod; } printf("%lld\n", ans); return 0; }