BZOJ 4174 - tty的求助
Published on 2016-08-18描述
给定整数 ,给定实数 ,请你求:
分析
首先一看这个式子显然不是什么好求的东西,我们试图对 求一个封闭形式,看看有什么发现:
中间的省略号略去了推导过程,关于详尽的推导过程,参见具体数学 P75。最关键的一步推导是这样的。对于 这个式子,让 ,最终得到的数按照某种方式排列之后一定是 ,后面跟着这个式子的 次重复,其中 。所以第一项和第三项都可以使用等差数列求和来搞定。
于是这个封闭形式中,我们发现可以用莫比乌斯反演来求:
由于只有一组,所以可以不用继续推导了,复杂度为 。
注意乘逆元!
代码
// Created by Sengxian on 8/16/16. // Copyright (c) 2016年 Sengxian. All rights reserved. // BZOJ 4174 莫比乌斯反演 + 推公式 #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 500000 + 3, modu = 998244353; int primes[maxn], mu[maxn], num; bool isPrime[maxn]; ll s[maxn], ss[maxn]; void sieve() { fill(isPrime, isPrime + maxn, 1); mu[1] = 1, num = 0; for (int i = 2; i < maxn; ++i) { if (isPrime[i]) primes[num++] = i, mu[i] = -1; static int d; for (int j = 0; j < num && (d = i * primes[j]) < maxn; ++j) { isPrime[d] = false; if (i % primes[j] == 0) { mu[d] = 0; break; } else mu[d] = -mu[i]; } } for (int i = 1; i < maxn; ++i) s[i] = s[i - 1] + mu[i]; } inline ll S(ll n) { return ((n + 1) * n >> 1) % modu; } inline ll G(ll n, ll m) { ll ans = 0; for (int i = 1, j = 1; i <= n; i = j + 1) { j = min(n / (n / i), m / (m / i)); (ans += (ll)(s[j] - s[i - 1]) * (n / i) % modu * (m / i) % modu) %= modu; } return ans; } inline int F(ll n, ll m, double x) { if (n > m) swap(n, m); ss[0] = 0; for (int i = 1; i <= n; ++i) ss[i] = 2 * i * (ll)floor(x / i) + i, (ss[i] += ss[i - 1]) %= modu; ll ans = (S(n - 1) * S(m - 1) % modu - n * m) % modu, tmp = 0; for (int i = 1, j = 1; i <= n; i = j + 1) { j = min(n / (n / i), m / (m / i)); tmp = G(n / i, m / i); (ans += (ss[j] - ss[i - 1]) * tmp % modu) %= modu; } ans *= 499122177LL; return (ans % modu + modu) % modu; } int main() { sieve(); int n, m; double x; scanf("%d%d%lf", &n, &m, &x); printf("%d\n", F(n, m, x)); return 0; }