题目描述
给定一个数组 ,求:
结果对 取模。
其中, 表示异或运算, 表示 的最小公倍数。
输入格式
第一行两个整数 表示数组长度。
第二行 个整数,第 个整数表示 。
输出格式
一个数字,表示取模后的结果。
输入样例
3
1 2 3
输出样例
18
提示
样例中 。
思路
首先,定义两个辅助函数:gcd 和 lcm,分别用于计算两个数的最大公约数和最小公倍数。
在主函数中,首先使用 memset 函数初始化 cnt 数组,将所有元素设置为0。
接着,从输入中读取数组长度 n,以及 n 个数组元素。对于每个读入的数组元素,增加其在 cnt 数组中的计数。
然后,进行两层循环,分别遍历 i 和 j。当 i 和 j 相等时,它们异或的结果总为0,不用计算这种情况。为了防止重复计算,让 j 始终大于 i。在每一次循环中,计算异或值 (i ^ j),最小公倍数 lcm(i, j),以及 cnt[i] 和 cnt[j] 的乘积。将这三者的乘积累加到 ans 中。
最后,输出累加后的结果 ans。
注意
计算时,每次计算乘法后需要立即对结果取模,防止溢出。
AC代码
#include <cstring>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;
const int N = 1e6 + 7;
const ll M = 1e9 + 7;
int n;
ll a[N], cnt[N];
ll gcd(ll x, ll y) { return (y == 0) ? (x) : (gcd(y, x % y)); }
ll lcm(ll x, ll y) { return x / gcd(x, y) * y; }
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
memset(cnt, 0, sizeof(cnt));
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[a[i]]++;
}
ll ans = 0;
for (ll i = 0; i <= 2e3; i++) {
for (ll j = i + 1; j <= 2e3; j++) {
ans = (ans + (i ^ j) * lcm(i, j) % M * cnt[i] % M * cnt[j] % M) % M;
}
}
cout << ans << "\n";
return 0;
}