SDOI2018 Round2 简要题解

Day 1

物理实验

转一下坐标系,扫描线,用set可以维护出每一段的最低位置能看到的线段的斜率,然后再双指针扫一遍就行了。

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 10005;
const LD eps = 1e-9;

struct Point {
  LD x, y;

  Point(LD x = 0, LD y = 0):x(x), y(y) {}

  Point operator - (const Point &b) const {
    return Point(x - b.x, y - b.y);
  }
} c, d, a[N], b[N];

struct Line {
  Point l, r;
  int i;

  Line(Point l = Point(0, 0), Point r = Point(0, 0), int i = -1):l(l), r(r), i(i) {}

  inline LD F(LD x) const {
    return ((x - l.x) * r.y + (r.x - x) * l.y) / (r.x - l.x);
  }

  inline LD S() const {
    return sqrt(1 + ((r.y - l.y) * (r.y - l.y)) / ((r.x - l.x) * (r.x - l.x)));
  }

  bool operator < (const Line &b) const {
    LD x = max(l.x, b.l.x);
    return fabs(F(x)) < fabs(b.F(x));
  }
} l[N];

LD all, ans, v[N << 1], x[N << 1];
pair int> eve[N << 1];
set  s, t;
int n, m;

int Main() {
  Read(n), m = 0, ans = 0, s.clear(), t.clear();
  for (int i = 1; i <= n; ++i) {
    Read(a[i].x), Read(a[i].y), Read(b[i].x), Read(b[i].y);
  }
  Read(c.x), Read(c.y), Read(d.x), Read(d.y), Read(all), d = d - c;
  LD p, q, len = sqrt(d.x * d.x + d.y * d.y);
  for (int i = 1; i <= n; ++i) {
    a[i] = a[i] - c;
    p = (d.x * a[i].x + d.y * a[i].y) / len, q = (d.x * a[i].y - d.y * a[i].x) / len;
    a[i] = Point(p, q);
    b[i] = b[i] - c;
    p = (d.x * b[i].x + d.y * b[i].y) / len, q = (d.x * b[i].y - d.y * b[i].x) / len;
    b[i] = Point(p, q);
    if (a[i].x > b[i].x) {
      swap(a[i], b[i]);
    }
    l[i] = Line(a[i], b[i], i);
    eve[i - 1 << 1] = mp(a[i].x, i), eve[i - 1 << 1 | 1] = mp(b[i].x, -i);
  }
  sort(eve, eve + (n << 1));
  for (int i = 0; i < n << 1; ++i) {
    if (!i || abs(eve[i].X - x[m - 1]) > eps) {
      x[m] = eve[i].X;
      if (m) {
        v[m - 1] = 0;
        if (!s.empty()) {
          v[m - 1] += s.begin()->S();
        }
        if (!t.empty()) {
          v[m - 1] += t.begin()->S();
        }
      }
      m++;
    }
    if (eve[i].Y > 0) {
      int p = eve[i].Y;
      if (a[p].y > 0) {
        s.insert(l[p]);
      } else {
        t.insert(l[p]);
      }
    } else {
      int p = -eve[i].Y;
      if (a[p].y > 0) {
        s.erase(l[p]);
      } else {
        t.erase(l[p]);
      }
    }
  }
  LD cur;
  cur = 0;
  for (int i = 0, j = 0; i < m; ++i) {
    for (; j + 1 < m && x[j + 1] < x[i] + all; ++j) {
      cur += (x[j + 1] - x[j]) * v[j];
    }
    CheckMax(ans, cur + (x[i] + all - x[j]) * (j == m - 1 ? 0 : v[j]));
    cur -= (x[i + 1] - x[i]) * v[i];
  }
  cur = 0;
  for (int i = m - 1, j = m - 1; ~i; --i) {
    for (; j && x[j - 1] > x[i] - all; --j) {
      cur += (x[j] - x[j - 1]) * v[j - 1];
    }
    CheckMax(ans, cur + (x[j] + all - x[i]) * (!j ? 0 : v[j - 1]));
    if (i) {
      cur -= (x[i] - x[i - 1]) * v[i - 1];
    }
  }
  printf("%.9Lf\n", ans);
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int T;
  for (Read(T); T; --T) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

战略游戏

建出圆方树,询问就是问虚树上圆点个数。

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 200005;
const int M = 20;

int n, m, q, ans, cnt, tim, top, dep[N], dfn[N], low[N], seq[N], siz[N], sta[N], sum[N], f[M][N];
vector <int> adj[N], adv[N];

inline void DFS(int x, int p) {
  dfn[x] = low[x] = ++tim, sta[++top] = x;
  bool f = false;
  for (auto y : adj[x]) {
    if (y != p || f) {
      if (!dfn[y]) {
        DFS(y, x), CheckMin(low[x], low[y]);
        if (dfn[x] <= low[y]) {
          ++m, adv[x].pb(m);
          for (int k = 0; k != y; adv[m].pb(k = sta[top--]));
        }
      } else {
        CheckMin(low[x], dfn[y]);
      }
    } else {
      f = true;
    }
  }
}

inline void DFS(int x) {
  dfn[x] = ++tim, siz[x] = 1, sum[x] = sum[f[0][x]] + (x <= n);
  for (int i = 1; i < M; ++i) {
    f[i][x] = f[i - 1][f[i - 1][x]];
  }
  for (auto y : adv[x]) {
    dep[y] = dep[x] + 1, f[0][y] = x, DFS(y), siz[x] += siz[y];
  }
}

inline int LCA(int x, int y) {
  if (dep[x] < dep[y]) {
    swap(x, y);
  }
  if (dep[x] > dep[y]) {
    for (int i = 0; i < M; ++i) {
      if (dep[x] - dep[y] >> i & 1) {
        x = f[i][x];
      }
    }
  }
  if (x == y) {
    return x;
  }
  for (int i = M - 1; ~i; --i) {
    if (f[i][x] != f[i][y]) {
      x = f[i][x], y = f[i][y];
    }
  }
  return f[0][x];
}

int Main() {
  Read(n), Read(m), tim = top = 0;
  for (int i = 1, x, y; i <= m; ++i) {
    Read(x), Read(y);
    adj[x].pb(y), adj[y].pb(x);
  }
  m = n, DFS(1, 0), tim = 0, DFS(1);
  for (Read(q); q; --q) {
    Read(cnt), ans = -cnt;
    for (int i = 1; i <= cnt; ++i) {
      Read(seq[i]);
    }
    sort(seq + 1, seq + cnt + 1, [&](const int &x, const int &y) {
      return dfn[x] < dfn[y];
    });
    for (int i = cnt; i > 1; --i) {
      seq[++cnt] = LCA(seq[i], seq[i - 1]);
    }
    sort(seq + 1, seq + cnt + 1, [&](const int &x, const int &y) {
      return dfn[x] < dfn[y];
    });
    cnt = unique(seq + 1, seq + cnt + 1) - seq - 1, top = 0;
    for (int i = 1; i <= cnt; ++i) {
      for (; top && !(dfn[sta[top]] <= dfn[seq[i]] && dfn[sta[top]] + siz[sta[top]] >= dfn[seq[i]] + siz[seq[i]]); --top);
      if (top) {
        ans += sum[f[0][seq[i]]] - sum[sta[top]];
      }
      sta[++top] = seq[i];
    }
    for (int i = 1; i <= cnt; ++i) {
      if (seq[i] <= n) {
        ++ans;
      }
    }
    printf("%d\n", ans);
  }
  for (int i = 1; i <= m; ++i) {
    adj[i].clear(), adv[i].clear(), dfn[i] = 0;
  }
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int T;
  for (Read(T); T; --T) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

反回文串

枚举串的周期 d d ,计算最短周期等于自身长度 d d 的串的个数记为 f f ,不难发现 f(n)=kn2d|nf(d) f ( n ) = k ⌈ n 2 ⌉ − ∑ d | n f ( d ) ,答案是 d|nf(d)(d1+[dmod2=0]) ∑ d | n f ( d ) ( d 1 + [ d mod 2 = 0 ] ) 。计算 f f 的时候可以发现它是一个类似积性函数的东西,推一推就可以算了。

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 200000;
const int M = 20;

LL n, k, a[N], pri[N];
int m, cnt, mod, b[N];

inline int Rand() {
#ifdef wxh010910
  return rand() << 15 | rand();
#else
  return rand();
#endif
}

inline LL RandLL() {
  return (LL)Rand() << 30 | Rand();
}

inline LL Qul(LL x, LL y, LL mod) {
  return ((x * y - (LL)(((LD)x * y + 0.5) / mod) * mod) % mod + mod) % mod;
}

inline LL Qow(LL x, LL y, LL mod) {
  LL r = 1;
  for (; y; y >>= 1, x = Qul(x, x, mod)) {
    if (y & 1) {
      r = Qul(r, x, mod);
    }
  }
  return r;
}

inline bool MillerRabin(LL n) {
  if (n == 2) {
    return true;
  }
  if (n < 2 || !(n & 1)) {
    return false;
  }
  LL a, x, y, u = n - 1;
  int t = 0;
  for (; !(u & 1); u >>= 1, ++t);
  for (int i = 0; i < 10; ++i) {
    a = RandLL() % (n - 1) + 1, x = Qow(a, u, n);
    for (int j = 0; j < t; ++j, x = y) {
      if ((y = Qul(x, x, n)) == 1 && x != 1 && x != n - 1) {
        return false;
      }
    }
    if (x != 1) {
      return false;
    }
  }
  return true;
}

inline LL PollardRho(LL a, LL c) {
  LL k = 2, x = RandLL() % a, y = x, p = 1;
  for (LL i = 1; p == 1; ++i) {
    x = (Qul(x, x, a) + c) % a, p = __gcd(abs(x - y), a);
    if (i == k) {
      y = x, k <<= 1;
    }
  }
  return p;
}

inline void Divide(LL x) {
  if (x == 1) {
    return ;
  }
  if (MillerRabin(x)) {
    pri[cnt++] = x;
    return ;
  }
  LL p = x;
  while (p >= x) {
    p = PollardRho(x, RandLL() % (x - 1));
  }
  Divide(p), Divide(x / p);
}

inline int Qow(int x, LL y) {
  int r = 1;
  for (; y; y >>= 1, x = 1LL * x * x % mod) {
    if (y & 1) {
      r = 1LL * r * x % mod;
    }
  }
  return r;
}

inline int DFS(int x, LL cur, int val) {
  if (x == m) {
    if (cur & 1) {
      return 1LL * cur % mod * Qow(k, cur + 1 >> 1) % mod * val % mod;
    } else {
      return 1LL * (cur >> 1) % mod * Qow(k, cur >> 1) % mod * val % mod;
    }
  }
  LL ans = 0, cof = 1LL * val * ((1 - a[x]) % mod + mod) % mod;
  if (a[x] & 1) {
    ans += DFS(x + 1, cur, cof);
  }
  for (int i = 1; i < b[x]; ++i) {
    ans += DFS(x + 1, cur *= a[x], cof);
  }
  ans += DFS(x + 1, cur *= a[x], val);
  return ans % mod;
}

int Main() {
  Read(n), Read(k), Read(mod), k %= mod, cnt = 0, Divide(n);
  sort(pri, pri + cnt), m = 0;
  for (int i = 0; i < cnt; ++i) {
    if (!i || pri[i] != pri[i - 1]) {
      a[m++] = pri[i], b[m - 1] = 0;
    }
    ++b[m - 1];
  }
  printf("%d\n", DFS(0, 1, 1));
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int T;
  for (Read(T); T; --T) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Day 2

原题识别

求出欧拉序,对于 (x,y) ( x , y ) ,我们在 (dfnx,dfny) ( d f n x , d f n y ) (endx,endy) ( e n d x , e n d y ) 两处权值加上 ansx,y a n s x , y ,在 (dfnx,endy) ( d f n x , e n d y ) (dfny,endx) ( d f n y , e n d x ) 处权值减去 ansx,y a n s x , y ,那么操作二就是询问一个子矩形的权值和。

考虑对每种颜色分别算贡献,将产生贡献的矩形暴力搞出来,然后离散化,然后暴力给全局打上标记即可。查询可以扫描线加树状数组解决。可以证明产生贡献的矩形个数期望是线性的。

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 200005;
const int M = 2005;

struct Event {
  int x, l, r, f;

  Event(int x = 0, int l = 0, int r = 0, int f = 0):x(x), l(l), r(r), f(f) {}

  bool operator < (const Event &b) const {
    return x < b.x;
  }
};

int n, m, t, cnt, a[N], s[N], p[N], q[N], dic[N], per[N], tag[M][M];
LL ans[N], bit[N], bitx[N], bity[N], bitxy[N];
vector  eve, qry;
vector <int> adj[N];
uint SA, SB, SC;

inline uint Rand() {
  SA ^= SA << 16, SA ^= SA >> 5, SA ^= SA << 1;
  uint t = SA;
  SA = SB, SB = SC, SC ^= t ^ SA;
  return SC;
}

inline void DFS(int x) {
  p[x] = ++t, s[t] = 1;
  for (auto y : adj[x]) {
    DFS(y);
  }
  q[x] = ++t, s[t] = -1;
}

inline void AddDic(int x) {
  dic[++cnt] = p[x] - 1, dic[++cnt] = q[x];
  for (auto y : adj[x]) {
    dic[++cnt] = p[y] - 1, dic[++cnt] = q[y];
  }
}

inline void AddTag(int xl, int xr, int yl, int yr, int f) {
  xl = lower_bound(dic, dic + cnt + 1, xl - 1) - dic + 1;
  yl = lower_bound(dic, dic + cnt + 1, yl - 1) - dic + 1;
  xr = lower_bound(dic, dic + cnt + 1, xr) - dic + 1;
  yr = lower_bound(dic, dic + cnt + 1, yr) - dic + 1;
  tag[xl][yl] += f, tag[xr][yr] += f;
  tag[xr][yl] -= f, tag[xl][yr] -= f;
}

inline void AddRec(int x) {
  AddTag(1, n << 1, p[x], q[x], 1);
  AddTag(p[x], q[x], 1, n << 1, 1);
  for (auto y : adj[x]) {
    AddTag(p[y], q[y], p[y], q[y], -2);
  }
}

inline void Modify(int x, int y, int a) {
  LL b = 1LL * a * s[x - 1], c = 1LL * a * s[y - 1], d = 1LL * a * s[x - 1] * s[y - 1];
  for (int i = y; i <= n << 1; i += i & -i) {
    bit[i] += a, bitx[i] += b, bity[i] += c, bitxy[i] += d;
  }
}

inline LL Query(int x, int y) {
  LL a = 0, b = 0, c = 0, d = 0;
  for (int i = y; i; i -= i & -i) {
    a += bit[i], b += bitx[i], c += bity[i], d += bitxy[i];
  }
  return a * s[x] * s[y] - b * s[y] - c * s[x] + d;
}

int Main() {
  Read(n), Read(m), Read(SA), Read(SB), Read(SC);
  eve.clear(), qry.clear(), t = 0;
  for (int i = 1; i <= n; ++i) {
    adj[i].clear(), per[i] = i;
  }
  for (int i = 2; i <= m; ++i) {
    adj[i - 1].pb(i);
  }
  for (int i = m + 1; i <= n; ++i) {
    adj[Rand() % (i - 1) + 1].pb(i);
  }
  for (int i = 1; i <= n; ++i) {
    a[i] = Rand() % n + 1;
  }
  DFS(1);
  for (int i = 1; i <= n << 1; ++i) {
    bit[i] = bitx[i] = bity[i] = bitxy[i] = 0;
    s[i] += s[i - 1];
  }
  sort(per + 1, per + n + 1, [&](const int &x, const int &y) {
    return a[x] < a[y];
  });
  for (int i = 1, j = 1; i <= n; i = j) {
    for (dic[0] = 0, dic[cnt = 1] = n << 1; j <= n && a[per[j]] == a[per[i]]; ++j);
    for (int k = i; k < j; ++k) {
      AddDic(per[k]);
    }
    sort(dic, dic + cnt + 1), cnt = unique(dic, dic + cnt + 1) - dic - 1;
    for (int k = 1; k <= cnt; ++k) {
      for (int l = 1; l <= cnt; ++l) {
        tag[k][l] = 0;
      }
    }
    for (int k = i; k < j; ++k) {
      AddRec(per[k]);
    }
    for (int k = 1; k <= cnt; ++k) {
      for (int l = 1; l <= cnt; ++l) {
        tag[k][l] += tag[k - 1][l] + tag[k][l - 1] - tag[k - 1][l - 1];
        if (tag[k][l]) {
          eve.pb(Event(dic[k - 1] + 1, dic[l - 1] + 1, dic[l], 1));
          eve.pb(Event(dic[k] + 1, dic[l - 1] + 1, dic[l], -1));
        }
      }
    }
  }
  Read(m);
  for (int i = 1, o, x, y, xl, xr, yl, yr; i <= m; ++i) {
    Read(o), Read(x), Read(y), ans[i] = 0;
    if (o == 1) {
      xl = xr = p[x], yl = yr = p[y];
    } else {
      xl = 1, xr = p[x], yl = 1, yr = p[y];
    }
    qry.pb(Event(xl - 1, yl, yr, -i));
    qry.pb(Event(xr, yl, yr, i));
  }
  sort(eve.begin(), eve.end());
  sort(qry.begin(), qry.end());
  for (int i = 0, j = 0; i < eve.size() || j < qry.size(); ) {
    if (i < eve.size() && (j == qry.size() || eve[i].x <= qry[j].x)) {
      Modify(eve[i].x, eve[i].l, eve[i].f);
      Modify(eve[i].x, eve[i].r + 1, -eve[i].f);
      ++i;
    } else {
      if (qry[j].f > 0) {
        ans[qry[j].f] += Query(qry[j].x, qry[j].r) - Query(qry[j].x, qry[j].l - 1);
      } else {
        ans[-qry[j].f] -= Query(qry[j].x, qry[j].r) - Query(qry[j].x, qry[j].l - 1);
      }
      ++j;
    }
  }
  for (int i = 1; i <= m; ++i) {
    printf("%lld\n", ans[i]);
  }
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int T;
  for (Read(T); T; --T) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

旧试题

根据rng_58恒等式,答案为 ijk[gcd(i,j)=1][gcd(i,k)=1][gcd(j,k)=1]AiBjCk ∑ i ∑ j ∑ k [ gcd ( i , j ) = 1 ] [ gcd ( i , k ) = 1 ] [ gcd ( j , k ) = 1 ] ⌊ A i ⌋ ⌊ B j ⌋ ⌊ C k ⌋

然后贴一下 蒜头的奖杯 代码就行了。

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 100005;
const int mod = 1e9 + 7;

int n, A, B, C, ans, tot, a[N], b[N], c[N], d[N], e[N], f[N], p[N], q[N], r[N], s[N], t[N], u[N], v[N], w[N], pri[N];
bool chk[N];

inline void F(int *a, int n) {
  for (int i = 1; i <= n; ++i) {
    for (int j = i + i; j <= n; j += i) {
      a[j] = (a[j] - a[i] + mod) % mod;
    }
  }
}

inline void G(int *a, int n) {
  for (int i = 1; pri[i] <= n; ++i) {
    for (int j = n / pri[i]; j; --j) {
      a[j] = (a[j] + a[j * pri[i]]) % mod;
    }
  }
}

inline void H(int *a, int n) {
  for (int i = 1; pri[i] <= n; ++i) {
    for (int j = 1; j * pri[i] <= n; ++j) {
      a[j * pri[i]] = (a[j * pri[i]] + a[j]) % mod;
    }
  }
}

int Main() {
  Read(A), Read(B), Read(C), n = max(max(A, B), C), ans = tot = 0;
  for (int i = 2; i <= n; ++i) {
    if (!chk[i]) {
      pri[++tot] = i;
    }
    for (int j = 1; i * pri[j] <= n; ++j) {
      chk[i * pri[j]] = true;
      if (i % pri[j] == 0) {
        break;
      }
    }
  }
  pri[tot + 1] = n + 1;
  for (int i = 1; i <= n; ++i) {
    a[i] = A / i, b[i] = B / i, c[i] = C / i, d[i] = e[i] = f[i] = i == 1;
  }
  G(c, n), F(e, n), F(f, n);
  for (int i = 1; i <= n; ++i) {
    int m = n / i;
    for (int j = 1; j <= m; ++j) {
      p[j] = e[i * j], q[j] = f[i * j], r[j] = c[i * j], s[j] = a[i * j], t[j] = b[i * j], w[j] = d[i * j];
    }
    F(w, m);
    for (int x = 1; x * x <= m; ++x) {
      for (int j = 1; j <= m; ++j) {
        u[j] = v[j] = 0;
      }
      for (int j = x; j <= m; j += x) {
        u[j] = s[j], v[j] = t[j];
      }
      G(u, m), G(v, m);
      for (int j = 1; j <= m; ++j) {
        u[j] = 1LL * u[j] * w[j] % mod, v[j] = 1LL * v[j] * w[j] % mod;
      }
      H(u, m), H(v, m);
      for (int j = 1; j <= m; ++j) {
        u[j] = 1LL * u[j] * t[j] % mod, v[j] = 1LL * v[j] * s[j] % mod;
      }
      for (int y = x; x * y <= m; ++y) {
        if (__gcd(x, y) == 1) {
          LL g = 0, h = 0;
          for (int j = y; j <= m; j += y) {
            g += u[j], h += v[j];
          }
          g %= mod, h %= mod;
          ans = (1LL * p[x] * q[y] % mod * r[x * y] % mod * g + ans) % mod;
          if (x != y) {
            ans = (1LL * p[y] * q[x] % mod * r[x * y] % mod * h + ans) % mod;
          }
        }
      }
    }
  }
  printf("%d\n", ans);
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int T;
  for (Read(T); T; --T) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

荣誉称号

不难发现只有前 2k+1 2 k + 1 个值有用,然后暴力树形DP就行了。

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 2050;
const int M = 205;
const LL inf = 1LL << 60;

int n, m, k, p, A, B, cur, lim, dis[N];
LL sum[N], f[N][M], g[N][M];
uint SA, SB, SC;

inline uint Rand() {
  SA ^= SA << 16, SA ^= SA >> 5, SA ^= SA << 1;
  uint t = SA;
  SA = SB, SB = SC, SC ^= t ^ SA;
  return SC;
}

inline void Modify(int i, int x, int y) {
  for (; i >> cur > lim; cur += k);
  i >>= cur, x %= m;
  sum[i] += y, g[i][0] += 1LL * (m - x) * y, g[i][x] -= m * y;
}

inline void DFS(int x) {
  if (x << 1 > lim) {
    for (int i = 0; i < m; ++i) {
      f[x][i] = g[x][i];
    }
    return ;
  }
  for (int i = 0; i < m; ++i) {
    f[x][i] = inf;
  }
  DFS(x << 1);
  if ((x << 1 | 1) > lim || dis[x << 1] != dis[x << 1 | 1]) {
    for (int i = 0; i < m; ++i) {
      for (int j = 0; j < m; ++j) {
        CheckMin(f[x][(i + j) % m], g[x][i] + f[x << 1][j]);
      }
    }
    return ;
  }
  DFS(x << 1 | 1);
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j < m; ++j) {
      CheckMin(f[x][(i + j) % m], g[x][i] + f[x << 1][j] + f[x << 1 | 1][j]);
    }
  }
}

int Main() {
  Read(n), Read(k), Read(m), Read(p), Read(SA), Read(SB), Read(SC), Read(A), Read(B), ++k, cur = 0, lim = min((1 << k) - 1, n);
  for (int i = 1; i <= lim; ++i) {
    sum[i] = 0;
    for (int j = 0; j < m; ++j) {
      g[i][j] = 0;
    }
  }
  for (int i = 1, x, y; i <= n; ++i) {
    if (i <= p) {
      Read(x), Read(y);
    } else {
      x = Rand() % A + 1, y = Rand() % B + 1;
    }
    Modify(i, x, y);
  }
  for (int i = 1; i <= lim; ++i) {
    for (int j = 1; j < m; ++j) {
      g[i][j] += g[i][j - 1];
    }
    for (int j = 1; j < m; ++j) {
      g[i][j] += sum[i] * j;
    }
  }
  for (int i = lim; i; --i) {
    dis[i] = i << 1 <= lim ? dis[i << 1] + 1 : 1;
  }
  DFS(1);
  printf("%lld\n", f[1][0]);
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int T;
  for (Read(T); T; --T) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

你可能感兴趣的:(SDOI2018 Round2 简要题解)