CF1845F Swimmers in the Pool 题解
思路
考虑两个人什么时候会相遇。
根据小学的相遇追及问题,两人会相遇的条件为:
\[2\times k\times l=t\times (v1+v2)
\]
\[2\times k\times l=t\times (v1-v2)
\]
那么对于一个速度 \(v\)。
它可一相遇的次数即为:
\[\frac{t\times v}{2\times l}
\]
当然,这样有可能会算重,也就是在相同的时间算了多次答案。
注意到若两个 \(v\) 有倍数关系,那么就会算重答案。
所以可以更改一下式子:
\[f_v=\frac{t\times v}{2\times l}-\sum_{i=1}^{i<v}[i|v] f_i
\]
可以直接枚举倍数计算。
至于如何求出所有的 \(v\) 是否等于 \(v1+v2\) 或者 \(v1-v2\)。
可以看作两个多项式:
\[f=x^{v_1}+x^{v_2}+x^{v_3}+x^{v_4}\cdots
\]
\[g=x^{-v_1}+x^{-v_2}+x^{-v_3}+x^{-v_4}\cdots
\]
算出 \(f\) 与 \(f\) 和 \(f\) 与 \(g\) 的卷积即可,可以使用 ntt 加速。
时间复杂度:\(O(v\ln v+v\log v)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
// #define int long long
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for(int i = (x); i <= (y); i++)
#define pre(i, x, y) for(int i = (x); i >= (y); i--)
inline void JYFILE19();
typedef long long i64;
typedef pair<int, int> PII;
bool ST;
const int N = 2e6 + 10;
const int M = 2e5;
const int mod = 998244353;
const int Mod = 1e9 + 7;
int l, t, n, ans, v[N], f[N], g[N], h[N], dp[N];
inline i64 power(i64 x, i64 y) {
i64 res = 1;
while(y) {
if(y & 1) res = res * x % mod;
x = x * x % mod, y /= 2;
}
return res;
}
struct ntt {
int m, tp, b[N], w[N];
int g = 3, ig = power(3, mod - 2);
#define Add(x, y) ((x + y >= mod) ? x + y - mod : x + y)
#define Sub(x, y) ((x - y >= 0) ? x - y : x - y + mod)
inline void init(int n) {
if(m == (1<<__lg(n)+1)) return; m = (1<<__lg(n)+1);
fro(i, 0, m - 1) b[i] = (b[i>>1]>>1)|((i&1)?m>>1:0);
}
inline void NTT(int *f, int n) {
init(n), w[0] = 1; int iv = (tp?power(m,mod-2):1);
fro(i, 1, m) if(i < b[i]) swap(f[i], f[b[i]]);
for(int p = 1; p < m; p <<= 1) {
int s = p<<1, b = power(tp?ig:g,(mod-1)/s);
for(int i = p - 2; i >= 0; i -= 2)
w[i | 1] = 1ll * b * (w[i] = w[i>>1]) % mod;
for(int i = 0; i < m; i += s) fro(j, 0, p - 1) {
int x = f[i + j], y = 1ll * f[i + j + p] * w[j] % mod;
f[i + j] = Add(x, y), f[i + j + p] = Sub(x, y);
}
}
if(tp) fro(i, 0, m - 1) f[i] = 1ll * f[i] * iv % mod;
}
inline void times(int *f, int *g, int n) {
tp = 0, NTT(f, n), NTT(g, n);
fro(i, 0, m - 1) f[i] = 1ll * f[i] * g[i] % mod;
tp = 1, NTT(f, n);
fill(g, g + m, 0);
fill(f + n + 1, f + m, 0);
}
} sol;
signed main() {
JYFILE19();
cin >> l >> t >> n;
fro(i, 1, n) cin >> v[i];
fro(i, 1, n) f[M + v[i]] = 1;
fro(i, 1, n) g[M + v[i]] = 1;
sol.times(f, g, M * 4);
fro(i, 0, M * 2) dp[i] = max(f[i + M * 2], dp[i]);
fro(i, 1, n) dp[v[i] * 2]--;
memset(f, 0, sizeof f);
memset(g, 0, sizeof g);
fro(i, 1, n) f[M + v[i]] = 1;
fro(i, 1, n) g[M - v[i]] = 1;
sol.times(f, g, M * 4);
fro(i, 0, M * 2) dp[i] = max(f[i + M * 2], dp[i]);
fro(i, 1, M * 2) {
for(int j = 1; j * i <= M * 2; j++) {
dp[i] = max(dp[i], dp[j * i]);
}
}
fro(i, 1, M * 2) {
(h[i] += (1ll * i * t / (l * 2)) % Mod) %= Mod;
for(int j = 2; j * i <= M * 2; j++)
(h[i * j] += Mod - h[i]) %= Mod;
if(dp[i] > 0) (ans += h[i]) %= Mod;
}
cout << ans << "\n";
return 0;
}
bool ED;
inline void JYFILE19() {
// freopen("", "r", stdin);
// freopen("", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
double MIB = fabs((&ED-&ST)/1048576.), LIM = 512;
cerr << "MEMORY: " << MIB << endl, assert(MIB<=LIM);
}