CF1845F Swimmers in the Pool 题解

思路#

考虑两个人什么时候会相遇。

根据小学的相遇追及问题,两人会相遇的条件为:

2×k×l=t×(v1+v2)

2×k×l=t×(v1v2)

那么对于一个速度 v

它可一相遇的次数即为:

t×v2×l

当然,这样有可能会算重,也就是在相同的时间算了多次答案。

注意到若两个 v 有倍数关系,那么就会算重答案。

所以可以更改一下式子:

fv=t×v2×li=1i<v[i|v]fi

可以直接枚举倍数计算。

至于如何求出所有的 v 是否等于 v1+v2 或者 v1v2

可以看作两个多项式:

f=xv1+xv2+xv3+xv4

g=xv1+xv2+xv3+xv4

算出 fffg 的卷积即可,可以使用 ntt 加速。

时间复杂度:O(vlnv+vlogv)

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

作者:JiaY19

出处:https://www.cnblogs.com/JiaY19/p/18028080

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   JiaY19  阅读(7)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示