題目連結
B
syh 喜歡貓貓,所以 zzy 為了哄 syh 睡覺,決定扮成貓貓。
給定一個長為 \(n\) 的序列 \(\{a_i\}\) 和三個正整數 \(x,y,z\),計算 \(\sum_{i=1}^n\sum_{j=1}^n a_ia_j\lfloor \dfrac{x\gcd(a_i,a_j)+y}{z} \rfloor\) 的值。答案對 \(10^9+7\) 取模。
如果這個問題的答案能夠被正確解出,zzy 就會學貓叫。由於 zzy 正在學怎麼學貓叫,所以請你告訴 syh 這個問題的答案。
賽時想到列舉 \(a[i]\) , 去找它的因子最為 \(gcd \ k\) , 再求\(\sum a_j\) (其中 \(gcd(a_i , a_j) = k\)).
將因子 \(k\) 從大到小列舉,這個 \(k\) 帶來的 \(\sum aj\) 可以預處理,不過要減去它在各個因子集合中倍數帶來的 \(\sum a_j\) 影響。
在列舉因子 \(k\) 倍數的時候就卡住了。
看了看榜一佬的思想,他把 \(a[i] * a[j]\) 整體看成了答案.
\(f[k]\) 代表 \(gcd = k\) 時,\(\sum a[i] * a[j]\).
之後就是類似於我們賽事的那個容斥思想了 (\(f[k]\) 不好求 , 求\(f[k >= i] - f[k > i]\))
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1E5 + 5;
const int mod = 1E9 + 7;
int n;
int num[N];
int f[N];
void solve() {
cin >> n;
LL x , y , z;
cin >> x >> y >> z;
for (int i = 1 ; i <= n ; ++i) {
int ai;
cin >> ai;
(num[ai] += ai) %= mod;
}
for (int i = 1 ; i < N ; ++i) {
for (int j = i ; j < N ; j += i) {
(f[i] += num[j]) %= mod;
}
}
for (int i = N - 1 ; i >= 1 ; --i) {
f[i] = 1LL * f[i] * f[i] % mod;
for (int j = i + i ; j < N ; j += i) {
f[i] -= f[j];
f[i] = (f[i] % mod + mod) % mod;
}
}
LL ans = 0;
for (int i = 1 ; i < N ; ++i) {
ans += 1LL * f[i] * ((x * i + y) / z) % mod;
ans %= mod;
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
while (T--) {
solve();
}
return 0;
}