華中農業大學第十三屆程式設計競賽

xqy2003發表於2024-04-14

題目連結


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;
}

相關文章