CodeForces Gym 102012 简要题解

Rikka with Minimum Spanning Trees

因为数据随机,所以MST只有 1 1 1 种。注意特判不连通的情况。

#include 

using namespace std;

typedef unsigned long long ull;

const int N = 123456;
const int md = 1e9 + 7;

struct edge_t {
  int from, to;
  ull cost;

  bool operator < (const edge_t &b) const {
    return cost < b.cost;
  }
} edge[N];

int n, m, p[N];
ull k1, k2;

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline int find(int x) {
  while (x != p[x]) {
    x = p[x] = p[p[x]];
  }
  return x;
}

inline ull xor_shift128_plus() {
  ull k3 = k1, k4 = k2;
  k1 = k4;
  k3 ^= k3 << 23;
  k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
  return k2 + k4;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d %d %llu %llu", &n, &m, &k1, &k2);
    for (int i = 0; i < m; ++i) {
      edge[i].from = xor_shift128_plus() % n;
      edge[i].to = xor_shift128_plus() % n;
      edge[i].cost = xor_shift128_plus();
    }
    sort(edge, edge + m);
    for (int i = 0; i < n; ++i) {
      p[i] = i;
    }
    int take = 0, answer = 0;
    for (int i = 0; i < m; ++i) {
      if (find(edge[i].from) != find(edge[i].to)) {
        p[find(edge[i].from)] = find(edge[i].to);
        add(answer, edge[i].cost % md);
        ++take;
      }
    }
    if (take < n - 1) {
      answer = 0;
    }
    printf("%d\n", answer);
  }
  return 0;
}

Rikka with Line Graphs

考虑求出 L 3 ( G ) L^3(G) L3(G) 中每个点的度数 d i d_i di ,那么 ∣ V ( L 5 ( G ) ) ∣ = ∑ ( d i 2 ) |V(L^5(G))|=\sum \binom{d_i}{2} V(L5(G))=(2di)

L 3 ( G ) L^3(G) L3(G) 中每个点是由两个 L 2 ( G ) L^2(G) L2(G) 中的点连起来的,而 L 2 ( G ) L^2(G) L2(G) 中的点表示的是共点的两条边,所以 L 3 ( G ) L^3(G) L3(G) 中的点可以表示为 ( ( e u , e v ) , ( e u , e w ) ) ((e_u,e_v),(e_u,e_w)) ((eu,ev),(eu,ew)) ,其中 ( e u , e v , e w ) (e_u,e_v,e_w) (eu,ev,ew) 是连通的三条边,而两个 L 3 ( G ) L^3(G) L3(G) 中的点有边当且仅当二元组有交。

分两种情况讨论:

  • e u = { u , v } e_u = \{u,v\} eu={u,v} e v e_v ev e w e_w ew e u e_u eu 上的公共顶点不同,记 e v = { u , w } , e w = { v , x } e_v = \{u, w\}, e_w = \{v, x\} ev={u,w},ew={v,x} ,那么可以推得它的度数为 3 d ( u ) + 3 d ( v ) + d ( w ) + d ( x ) − 14 3d(u)+3d(v)+d(w)+d(x)-14 3d(u)+3d(v)+d(w)+d(x)14
  • e u = { u , v } e_u = \{u, v\} eu={u,v} e v e_v ev e w e_w ew e u e_u eu 上的公共顶点相同,记 e v = { u , w } , e w = { u , x } e_v = \{u, w\}, e_w = \{u, x\} ev={u,w},ew={u,x} ,那么可以推得它的度数为 4 d ( u ) + 2 d ( v ) + d ( w ) + d ( x ) − 14 4d(u)+2d(v)+d(w)+d(x)-14 4d(u)+2d(v)+d(w)+d(x)14

展开 ( d i 2 ) \binom{d_i}{2} (2di) ,两种情况分别讨论:

Case 1:

9 u 2 + 9 v 2 + w 2 + x 2 + 18 u v + 6 u w + 6 u x + 6 v w + 6 v x + 2 w x + 210 − 87 u − 87 v − 29 w − 29 x 9u^2+9v^2+w^2+x^2+18uv+6uw+6ux+6vw+6vx+2wx+210-87u-87v-29w-29x 9u2+9v2+w2+x2+18uv+6uw+6ux+6vw+6vx+2wx+21087u87v29w29x

(这里 u u u 实际表示的是 d ( u ) d(u) d(u)

为了方便我们把 ( u , v ) (u,v) (u,v) 搞成无序的,最后答案除以 2 2 2 即可。

为了描述方便, f → g f\to g fg 表示令 f x = ∑ y ∈ a d j x g y f_x = \sum_{y\in adj_x} g_y fx=yadjxgy

s d → d , s s d → d 2 , s s s d → d 3 , t d → s d , t t d → s s d , r d → d × s d sd\to d, ssd\to d^2, sssd\to d^3, td\to sd, ttd\to ssd, rd\to d\times sd sdd,ssdd2,sssdd3,tdsd,ttdssd,rdd×sd

1 , u , u 2 1,u,u^2 1,u,u2 的系数: ( d ( u ) − 1 ) ∑ v ( d ( v ) − 1 ) = ( d ( u ) − 1 ) ( s d ( u ) − d ( u ) ) (d(u)-1)\sum_v(d(v)-1)=(d(u)-1)(sd(u)-d(u)) (d(u)1)v(d(v)1)=(d(u)1)(sd(u)d(u))

v , u v v,uv v,uv 的系数: ( d ( u ) − 1 ) ∑ v ( d ( v ) − 1 ) d ( v ) = ( d ( u ) − 1 ) ( s s d ( u ) − s d ( u ) ) (d(u)-1)\sum_v(d(v)-1)d(v) = (d(u)-1)(ssd(u)-sd(u)) (d(u)1)v(d(v)1)d(v)=(d(u)1)(ssd(u)sd(u))

v 2 v^2 v2 的系数: ( d ( u ) − 1 ) ( s s s d ( u ) − s s d ( u ) ) (d(u)-1)(sssd(u)-ssd(u)) (d(u)1)(sssd(u)ssd(u))

w , u w w,uw w,uw 的系数: ∑ v ( d ( v ) − 1 ) ( s d ( u ) − d ( v ) ) = s d ( u ) 2 − s s d ( u ) − d ( u ) s d ( u ) + s d ( u ) \sum_v (d(v)-1)(sd(u)-d(v))=sd(u)^2-ssd(u)-d(u)sd(u)+sd(u) v(d(v)1)(sd(u)d(v))=sd(u)2ssd(u)d(u)sd(u)+sd(u)

w 2 w^2 w2 的系数: ∑ v ( d ( v ) − 1 ) ( s s d ( u ) − d ( v ) 2 ) = s s d ( u ) s d ( u ) − s s s d ( u ) − d ( u ) s s d ( u ) + s s d ( u ) \sum_v (d(v)-1)(ssd(u)-d(v)^2)=ssd(u)sd(u)-sssd(u)-d(u)ssd(u)+ssd(u) v(d(v)1)(ssd(u)d(v)2)=ssd(u)sd(u)sssd(u)d(u)ssd(u)+ssd(u)

x , u x x,ux x,ux 的系数: ( d ( u ) − 1 ) ( ∑ v s d ( v ) − d ( u ) ) = ( d ( u ) − 1 ) ( t d ( u ) − d ( u ) 2 ) (d(u)-1)(\sum_{v} sd(v)-d(u))=(d(u)-1)(td(u)-d(u)^2) (d(u)1)(vsd(v)d(u))=(d(u)1)(td(u)d(u)2)

x 2 x^2 x2 的系数: ( d ( u ) − 1 ) ( ∑ v s s d ( v ) − d ( u ) 2 ) = ( d ( u ) − 1 ) ( t t d ( u ) − d ( u ) 3 ) (d(u)-1)(\sum_v ssd(v)-d(u)^2)=(d(u)-1)(ttd(u)-d(u)^3) (d(u)1)(vssd(v)d(u)2)=(d(u)1)(ttd(u)d(u)3)

v w vw vw 的系数: ∑ v ( d ( v ) 2 − d ( v ) ) ( s d ( u ) − d ( v ) ) = s d ( u ) s s d ( u ) − s d ( u ) 2 − s s s d ( u ) + s s d ( u ) \sum_v (d(v)^2-d(v))(sd(u)-d(v))=sd(u)ssd(u)-sd(u)^2-sssd(u)+ssd(u) v(d(v)2d(v))(sd(u)d(v))=sd(u)ssd(u)sd(u)2sssd(u)+ssd(u)

v x vx vx 的系数: ( d ( u ) − 1 ) ∑ v d ( v ) ( s d ( v ) − d ( u ) ) = ( d ( u ) − 1 ) ( r d ( u ) − d ( u ) s d ( u ) ) (d(u)-1)\sum_v d(v)(sd(v)-d(u))=(d(u)-1)(rd(u)-d(u)sd(u)) (d(u)1)vd(v)(sd(v)d(u))=(d(u)1)(rd(u)d(u)sd(u))

x w xw xw 的系数: ∑ v ( s d ( v ) − d ( u ) ) ( s d ( u ) − d ( v ) ) = s d ( u ) t d ( u ) + d ( u ) s d ( u ) − d ( u ) 2 s d ( u ) − r d ( u ) \sum_v (sd(v)-d(u))(sd(u)-d(v))=sd(u)td(u)+d(u)sd(u)-d(u)^2sd(u)-rd(u) v(sd(v)d(u))(sd(u)d(v))=sd(u)td(u)+d(u)sd(u)d(u)2sd(u)rd(u)

Case 2:

16 u 2 + 4 v 2 + w 2 + x 2 + 16 u v + 8 u w + 8 u x + 4 v w + 4 v x + 2 w x + 210 − 116 u − 58 v − 29 w − 29 x 16u^2+4v^2+w^2+x^2+16uv+8uw+8ux+4vw+4vx+2wx+210-116u-58v-29w-29x 16u2+4v2+w2+x2+16uv+8uw+8ux+4vw+4vx+2wx+210116u58v29w29x

为了方便我们把 ( w , x ) (w,x) (w,x) 搞成无序的,最后答案除以 2 2 2 即可。

1 , u , u 2 1,u,u^2 1,u,u2 的系数: d ( u ) ( d ( u ) − 1 ) ( d ( u ) − 2 ) d(u)(d(u)-1)(d(u)-2) d(u)(d(u)1)(d(u)2)

v , u v , w , u w , x , u x v,uv,w,uw,x,ux v,uv,w,uw,x,ux 的系数: s d ( u ) ( d ( u ) − 1 ) ( d ( u ) − 2 ) sd(u)(d(u)-1)(d(u)-2) sd(u)(d(u)1)(d(u)2)

v 2 , w 2 , x 2 v^2,w^2,x^2 v2,w2,x2 的系数: s s d ( u ) ( d ( u ) − 1 ) ( d ( u ) − 2 ) ssd(u)(d(u)-1)(d(u)-2) ssd(u)(d(u)1)(d(u)2)

v w , v x , x w vw,vx,xw vw,vx,xw 的系数: ( d ( u ) − 2 ) ∑ v d ( v ) ( s d ( u ) − d ( v ) ) = ( d ( u ) − 2 ) ( s d ( u ) 2 − s s d ( u ) ) (d(u)-2)\sum_v d(v)(sd(u)-d(v))=(d(u)-2)(sd(u)^2-ssd(u)) (d(u)2)vd(v)(sd(u)d(v))=(d(u)2)(sd(u)2ssd(u))

考虑求 L 6 ( G ) L^6(G) L6(G) ,相当于求 G G G 中每条边的 d , s d , ⋯ d, sd, \cdots d,sd, ,跟一条边相邻的点可以用跟两个端点相邻的边减去它自身的贡献来计算,然后就做完了。

#include 

using namespace std;

const int N = 234567;
const int md = 1e9 + 7;

int d[N], sd[N], ssd[N], sssd[N], td[N], ttd[N], rd[N];
int v[N], sv[N], ssv[N], sssv[N], tv[N], ttv[N], rv[N];
int n, m, from[N], to[N];

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (long long)x * y % md;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; ++i) {
      v[i] = sv[i] = ssv[i] = sssv[i] = tv[i] = ttv[i] = rv[i] = 0;
    }
    for (int i = 0; i < m; ++i) {
      scanf("%d %d", &from[i], &to[i]);
      --from[i];
      --to[i];
      ++v[from[i]];
      ++v[to[i]];
    }
    for (int i = 0; i < m; ++i) {
      d[i] = v[from[i]] + v[to[i]] - 2;
      add(sv[from[i]], d[i]);
      add(sv[to[i]], d[i]);
      add(ssv[from[i]], mul(d[i], d[i]));
      add(ssv[to[i]], mul(d[i], d[i]));
      add(sssv[from[i]], mul(d[i], mul(d[i], d[i])));
      add(sssv[to[i]], mul(d[i], mul(d[i], d[i])));
    }
    for (int i = 0; i < m; ++i) {
      sd[i] = ((sv[from[i]] + sv[to[i]] - d[i] * 2) % md + md) % md;
      ssd[i] = ((ssv[from[i]] + ssv[to[i]] - mul(d[i], d[i]) * 2) % md + md) % md;
      sssd[i] = ((sssv[from[i]] + sssv[to[i]] - mul(d[i], mul(d[i], d[i])) * 2) % md + md) % md;
      add(tv[from[i]], sd[i]);
      add(tv[to[i]], sd[i]);
      add(ttv[from[i]], ssd[i]);
      add(ttv[to[i]], ssd[i]);
      add(rv[from[i]], mul(d[i], sd[i]));
      add(rv[to[i]], mul(d[i], sd[i]));
    }
    for (int i = 0; i < m; ++i) {
      td[i] = ((tv[from[i]] + tv[to[i]] - sd[i] * 2) % md + md) % md;
      ttd[i] = ((ttv[from[i]] + ttv[to[i]] - ssd[i] * 2) % md + md) % md;
      rd[i] = ((rv[from[i]] + rv[to[i]] - mul(d[i], sd[i]) * 2) % md + md) % md;
    }
    int answer = 0;
    for (int i = 0; i < m; ++i) {
      int coef;
      // case 1
      {
        // 1, u, u^2
        coef = mul(d[i] + md - 1, sd[i] + md - d[i]);
        add(answer, mul(coef, mul(9, mul(d[i], d[i])) + md - mul(87, d[i]) + 210));
        // v, uv
        coef = mul(d[i] + md - 1, ssd[i] + md - sd[i]);
        add(answer, mul(coef, mul(18, d[i]) + md - 87));
        // v^2
        coef = mul(d[i] + md - 1, sssd[i] + md - ssd[i]);
        add(answer, mul(coef, 9));
        // w, uw
        coef = 0;
        add(coef, mul(sd[i], sd[i]));
        add(coef, sd[i]);
        sub(coef, ssd[i]);
        sub(coef, mul(d[i], sd[i]));
        add(answer, mul(coef, mul(6, d[i]) + md - 29));
        // w^2
        coef = 0;
        add(coef, mul(ssd[i], sd[i]));
        add(coef, ssd[i]);
        sub(coef, sssd[i]);
        sub(coef, mul(d[i], ssd[i]));
        add(answer, coef);
        // x, ux
        coef = mul(d[i] + md - 1, td[i] + md - mul(d[i], d[i]));
        add(answer, mul(coef, mul(6, d[i]) + md - 29));
        // x^2
        coef = mul(d[i] + md - 1, ttd[i] + md - mul(d[i], mul(d[i], d[i])));
        add(answer, coef);
        // vw
        coef = 0;
        add(coef, mul(sd[i], ssd[i]));
        add(coef, ssd[i]);
        sub(coef, sssd[i]);
        sub(coef, mul(sd[i], sd[i]));
        add(answer, mul(coef, 6));
        // vx
        coef = mul(d[i] + md - 1, rd[i] + md - mul(d[i], sd[i]));
        add(answer, mul(coef, 6));
        // xw
        coef = 0;
        add(coef, mul(sd[i], td[i]));
        add(coef, mul(sd[i], d[i]));
        sub(coef, rd[i]);
        sub(coef, mul(sd[i], mul(d[i], d[i])));
        add(answer, mul(coef, 2));
      }
      // case 2
      {
        // 1, u, u^2
        coef = mul(d[i], mul(d[i] + md - 1, d[i] + md - 2));
        add(answer, mul(coef, mul(16, mul(d[i], d[i])) + md - mul(116, d[i]) + 210));
        // v, uv, w, uw, x, ux
        coef = mul(sd[i], mul(d[i] + md - 1, d[i] + md - 2));
        add(answer, mul(coef, mul(32, d[i]) + md - 116));
        // v^2, w^2, x^2
        coef = mul(ssd[i], mul(d[i] + md - 1, d[i] + md - 2));
        add(answer, mul(coef, 6));
        // vw, vx, xw
        coef = mul(d[i] + md - 2, mul(sd[i], sd[i]) + md - ssd[i]);
        add(answer, mul(coef, 10));
      }
    }
    answer = mul(answer, md + 1 >> 2);
    printf("%d\n", answer);
  }
  return 0;
}

Rikka with Consistency

f ( x , y , h ) f(x,y,h) f(x,y,h) 表示第一个人在 [ x , x + 1 ] [x,x+1] [x,x+1] 这一段,第二个人在 [ y , y + 1 ] [y,y+1] [y,y+1] 这一段,高度为 h h h 时的最小距离,跑个最短路即可。

#include 

using namespace std;

typedef double ld;

const int N = 56;
const int MAX = 50;

priority_queue<pair<ld, tuple<int, int, int>>> q;
ld unit[N][N], dist[N][N][N];
bool visit[N][N][N];
int n, a[N];

void update(int x, int y, int z, ld value) {
  if (dist[x][y][z] > value) {
    dist[x][y][z] = value;
    q.emplace(-value, make_tuple(x, y, z));
  }
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  for (int i = 0; i <= MAX; ++i) {
    for (int j = 0; j <= MAX; ++j) {
      if (i != j) {
        unit[i][j] = sqrt(abs(i - j) * abs(i - j) + 1) / abs(i - j);
      }
    }
  }
  while (tt--) {
    scanf("%d", &n);
    for (int i = 0; i <= n; ++i) {
      scanf("%d", &a[i]);
    }
    for (int i = 0; i <= n; ++i) {
      for (int j = 0; j <= n; ++j) {
        for (int k = 0; k <= MAX; ++k) {
          dist[i][j][k] = 1e9;
          visit[i][j][k] = false;
        }
      }
    }
    dist[0][n][0] = 0;
    q.emplace(0, make_tuple(0, n, 0));
    while (!q.empty()) {
      int x = get<0>(q.top().second);
      int y = get<1>(q.top().second);
      int z = get<2>(q.top().second);
      q.pop();
      if (visit[x][y][z]) {
        continue;
      }
      visit[x][y][z] = true;
      if (x && a[x] == z) {
        update(x - 1, y, z, dist[x][y][z] + (a[x - 1] == a[x]));
      }
      if (x < n && a[x + 1] == z) {
        update(x + 1, y, z, dist[x][y][z] + (a[x + 1] == a[x]));
      }
      if (y && a[y] == z) {
        update(x, y - 1, z, dist[x][y][z] + (a[y - 1] == a[y]));
      }
      if (y < n && a[y + 1] == z) {
        update(x, y + 1, z, dist[x][y][z] + (a[y + 1] == a[y]));
      }
      if (x < n && y < n) {
        if (min(a[x + 1], a[x]) <= z - 1 && max(a[x + 1], a[x]) >= z - 1 && min(a[y + 1], a[y]) <= z - 1 && max(a[y + 1], a[y]) >= z - 1) {
          update(x, y, z - 1, dist[x][y][z] + unit[a[x + 1]][a[x]] + unit[a[y + 1]][a[y]]);
        }
        if (min(a[x + 1], a[x]) <= z + 1 && max(a[x + 1], a[x]) >= z + 1 && min(a[y + 1], a[y]) <= z + 1 && max(a[y + 1], a[y]) >= z + 1) {
          update(x, y, z + 1, dist[x][y][z] + unit[a[x + 1]][a[x]] + unit[a[y + 1]][a[y]]);
        }
      }
    }
    printf("%.10lf\n", dist[n][0][0]);
  }
  return 0;
}

Rikka with Subsequences

将三方用组合意义拆开,变成枚举三个相同的子序列,记 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示第一个数组最后一个匹配的是 i i i ,第二个是 j j j ,第三个是 k k k ,前缀和优化转移即可。

#include 

using namespace std;

const int N = 234;
const int md = 1e9 + 7;

int n, a[N], dp[N][N], sum[N][N];
char board[N][N];

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
      scanf("%d", &a[i]);
      --a[i];
    }
    for (int i = 0; i < n; ++i) {
      scanf("%s", board[i]);
    }
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        dp[i][j] = 0;
      }
    }
    int answer = 0;
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        for (int k = 0; k < n; ++k) {
          sum[j + 1][k + 1] = board[a[j]][a[i]] == '1' ? dp[j][k] : 0;
          add(sum[j + 1][k + 1], sum[j + 1][k]);
          add(sum[j + 1][k + 1], sum[j][k + 1]);
          sub(sum[j + 1][k + 1], sum[j][k]);
        }
      }
      for (int j = 0; j < n; ++j) {
        for (int k = 0; k < n; ++k) {
          if (a[i] == a[j] && a[i] == a[k]) {
            int ways = 1;
            add(ways, sum[j][k]);
            add(answer, ways);
            add(dp[j][k], ways);
          }
        }
      }
    }
    printf("%d\n", answer);
  }
  return 0;
}

Rikka with Data Structures

李超树。

#include 

using namespace std;

class segtree_t {
 public:
  struct node_t {
    long long add = 0, cover = 0, value = 0, go_l = 0, go_r = 0;
    
    void apply(int l, int r, long long ad, long long co) {
      if (co) {
        add = 0;
        cover = co;
        value = co;
        go_l = go_r = r - l + 1;
      } else {
        if (cover) {
          cover += ad;
        } else {
          add += ad;
        }
        value += ad;
      }
    }
  };
  
  vector<node_t> tree;
  int n;

  segtree_t(int n):n(n) {
    tree.resize((n << 1) - 1);
  }

  inline void pull(int x, int l, int r) {
    int y = l + r >> 1, z = x + (y - l + 1 << 1);
    tree[x].value = max(tree[x + 1].value, tree[z].value);
    tree[x].go_l = tree[z].go_l + query_l(x + 1, l, y, tree[z].value);
    tree[x].go_r = tree[x + 1].go_r + query_r(z, y + 1, r, tree[x + 1].value);
  }

  inline void push(int x, int l, int r) {
    int y = l + r >> 1, z = x + (y - l + 1 << 1);
    if (tree[x].add || tree[x].cover) {
      tree[x + 1].apply(l, y, tree[x].add, tree[x].cover);
      tree[z].apply(y + 1, r, tree[x].add, tree[x].cover);
      tree[x].add = tree[x].cover = 0;
    }
  }

  template<typename T> void build(int x, int l, int r, const vector<T> &v) {
    if (l == r) {
      tree[x].apply(l, r, 0, v[l]);
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      build(x + 1, l, y, v);
      build(z, y + 1, r, v);
      pull(x, l, r);
    }
  }

  template<typename T> void build(const vector<T> &v) {
    build(0, 0, n - 1, v);
  }

  template<typename... T> void modify(int x, int l, int r, int ql, int qr, const T&... v) {
    if (l == ql && r == qr) {
      tree[x].apply(l, r, v...);
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (qr <= y) {
        modify(x + 1, l, y, ql, qr, v...);
      } else if (ql > y) {
        modify(z, y + 1, r, ql, qr, v...);
      } else {
        modify(x + 1, l, y, ql, y, v...);
        modify(z, y + 1, r, y + 1, qr, v...);
      }
      pull(x, l, r);
    }
  }

  template<typename... T> void modify(int l, int r, const T&... v) {
    modify(0, 0, n - 1, l, r, v...);
  }

  long long query_value(int x, int l, int r, int ql, int qr) {
    if (l == ql && r == qr) {
      return tree[x].value;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (qr <= y) {
        return query_value(x + 1, l, y, ql, qr);
      } else if (ql > y) {
        return query_value(z, y + 1, r, ql, qr);
      } else {
        return max(query_value(x + 1, l, y, ql, y), query_value(z, y + 1, r, y + 1, qr));
      }
    }
  }

  long long query_value(int l, int r) {
    return query_value(0, 0, n - 1, l, r);
  }

  int query_l(int x, int l, int r, long long v) {
    if (v > tree[x].value) {
      return 0;
    } else if (l == r) {
      return 1;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (v > tree[z].value) {
        return query_l(x + 1, l, y, v);
      } else {
        return query_l(z, y + 1, r, v) + tree[x].go_l - tree[z].go_l;
      }
    }
  }

  int query_l(int x, int l, int r, int ql, int qr, long long &v) {
    if (l == ql && r == qr) {
      int result = query_l(x, l, r, v);
      v = max(v, tree[x].value);
      return result;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (qr <= y) {
        return query_l(x + 1, l, y, ql, qr, v);
      } else if (ql > y) {
        return query_l(z, y + 1, r, ql, qr, v);
      } else {
        int result = query_l(z, y + 1, r, y + 1, qr, v);
        result += query_l(x + 1, l, y, ql, y, v);
        return result;
      }
    }
  }

  int query_l(int l, int r, long long v) {
    return query_l(0, 0, n - 1, l, r, v);
  }

  int query_r(int x, int l, int r, long long v) {
    if (v > tree[x].value) {
      return 0;
    } else if (l == r) {
      return 1;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (v > tree[x + 1].value) {
        return query_r(z, y + 1, r, v);
      } else {
        return query_r(x + 1, l, y, v) + tree[x].go_r - tree[x + 1].go_r;
      }
    }
  }

  int query_r(int x, int l, int r, int ql, int qr, long long &v) {
    if (l == ql && r == qr) {
      int result = query_r(x, l, r, v);
      v = max(v, tree[x].value);
      return result;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (qr <= y) {
        return query_r(x + 1, l, y, ql, qr, v);
      } else if (ql > y) {
        return query_r(z, y + 1, r, ql, qr, v);
      } else {
        int result = query_r(x + 1, l, y, ql, y, v);
        result += query_r(z, y + 1, r, y + 1, qr, v);
        return result;
      }
    }
  }

  int query_r(int l, int r, long long v) {
    return query_r(0, 0, n - 1, l, r, v);
  }

  int find_l(int x, int l, int r, int p, long long v) {
    if (v >= tree[x].value) {
      return -1;
    } else if (l == r) {
      return l;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (p > y) {
        int result = find_l(z, y + 1, r, p, v);
        if (~result) {
          return result;
        }
      }
      return find_l(x + 1, l, y, p, v);
    }
  }

  int find_l(int p, long long v) {
    return find_l(0, 0, n - 1, p, v);
  }

  int find_r(int x, int l, int r, int p, long long v) {
    if (v >= tree[x].value) {
      return n;
    } else if (l == r) {
      return r;
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, l, r);
      if (p <= y) {
        int result = find_r(x + 1, l, y, p, v);
        if (result != n) {
          return result;
        }
      }
      return find_r(z, y + 1, r, p, v);
    }
  }

  int find_r(int p, long long v) {
    return find_r(0, 0, n - 1, p, v);
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    int n, m;
    scanf("%d %d", &n, &m);
    segtree_t segtree(n);
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
      scanf("%d", &a[i]);
    }
    segtree.build(a);
    while (m--) {
      int type, l, r, x;
      scanf("%d %d %d %d", &type, &l, &r, &x);
      --l;
      --r;
      if (type == 1) {
        segtree.modify(l, r, x, 0);
      } else if (type == 2) {
        segtree.modify(l, r, 0, x);
      } else {
        --x;
        long long value = segtree.query_value(x, x);
        int answer = 0;
        if (x < l) {
          int p = segtree.find_r(x + 1, value);
          answer += max(min(p - 1, r) - l + 1, 0);
          answer += segtree.query_r(l, r, max(value + 1, segtree.query_value(x, l)));
        } else if (x > r) {
          int p = segtree.find_l(x - 1, value);
          answer += max(r - max(p + 1, l) + 1, 0);
          answer += segtree.query_l(l, r, max(value + 1, segtree.query_value(r, x)));
        } else {
          answer = 1;
          answer += segtree.query_l(l, x, value + 1);
          answer += segtree.query_r(x, r, value + 1);
          if (x) {
            int p = segtree.find_l(x - 1, value);
            answer += max((x - 1) - max(p + 1, l) + 1, 0);
          }
          if (x + 1 < n) {
            int p = segtree.find_r(x + 1, value);
            answer += max(min(p - 1, r) - (x + 1) + 1, 0);
          }
        }
        printf("%d\n", answer);
      }
    }
  }
  return 0;
}

Rikka with Nice Counting Striking Back

相当于对于串 $s, ss, sss\cdots $ 我们只计算一次,那么求出所有 primitive square 后减去多算的即可。

#include 

using namespace std;

template<typename T> vector<int> suffix_array(const T &s, int n, int alpha) {
  vector<int> a(n);
  if (~alpha) {
    vector<int> bucket(alpha);
    for (int i = 0; i < n; ++i) {
      ++bucket[s[i]];
    }
    int sum = 0;
    for (int i = 0; i < alpha; ++i) {
      int add = bucket[i];
      bucket[i] = sum;
      sum += add;
    }
    for (int i = 0; i < n; ++i) {
      a[bucket[s[i]]++] = i;
    }
  } else {
    for (int i = 0; i < n; ++i) {
      a[i] = i;
    }
    sort(a.begin(), a.end(), [&](const int &x, const int &y) {
      return s[x] < s[y];
    });
  }
  vector<int> sorted_by_second(n);
  vector<int> ptr_group(n);
  vector<int> new_group(n);
  vector<int> group(n);
  group[a[0]] = 0;
  for (int i = 1; i < n; ++i) {
    group[a[i]] = group[a[i - 1]] + (s[a[i]] != s[a[i - 1]]);
  }
  int step = 1;
  while (group[a[n - 1]] < n - 1) {
    int ptr = 0;
    for (int i = n - step; i < n; ++i) {
      sorted_by_second[ptr++] = i;
    }
    for (int i = 0; i < n; ++i) {
      if (a[i] >= step) {
        sorted_by_second[ptr++] = a[i] - step;
      }
    }
    for (int i = n - 1; ~i; --i) {
      ptr_group[group[a[i]]] = i;
    }
    for (int i = 0; i < n; ++i) {
      int x = sorted_by_second[i];
      a[ptr_group[group[x]]++] = x;
    }
    new_group[a[0]] = 0;
    for (int i = 1; i < n; ++i) {
      if (group[a[i]] != group[a[i - 1]]) {
        new_group[a[i]] = new_group[a[i - 1]] + 1;
      } else {
        int prev = a[i - 1] + step >= n ? -1 : group[a[i - 1] + step];
        int now = a[i] + step >= n ? -1 : group[a[i] + step];
        new_group[a[i]] = new_group[a[i - 1]] + (prev != now);
      }
    }
    group = new_group;
    step <<= 1;
  }
  return a;
}

template<typename T> vector<int> build_lcp(const T &s, int n, const vector<int> &sa) {
  vector<int> pos(n);
  for (int i = 0; i < n; ++i) {
    pos[sa[i]] = i;
  }
  vector<int> lcp(n - 1);
  for (int i = 0, k = 0; i < n; ++i) {
    k = max(k - 1, 0);
    if (pos[i] == n - 1) {
      k = 0;
    } else {
      int j = sa[pos[i] + 1];
      while (i + k < n && j + k < n && s[i + k] == s[j + k]) {
        ++k;
      }
      lcp[pos[i]] = k;
    }
  }
  return lcp;
}

class lcp_query_t {
 public:
  vector<vector<int>> rmq;
  vector<int> pos, zeros;
  int n;

  lcp_query_t(vector<int> sa, vector<int> lcp) {
    n = sa.size();
    zeros.resize(n);
    for (int i = 2; i < n; ++i) {
      zeros[i] = zeros[i >> 1] + 1;
    }
    pos.resize(n);
    for (int i = 0; i < n; ++i) {
      pos[sa[i]] = i;
    }
    int max_log = zeros[n - 1] + 1;
    rmq.resize(max_log);
    for (int i = 0; i < max_log; ++i) {
      rmq[i].resize(n - 1);
    }
    for (int i = 0; i < n - 1; ++i) {
      rmq[0][i] = lcp[i];
    }
    for (int i = 1; i < max_log; ++i) {
      for (int j = 0; j + (1 << i) <= n - 1; ++j) {
        rmq[i][j] = min(rmq[i - 1][j], rmq[i - 1][j + (1 << i - 1)]);
      }
    }
  }

  int get_lcp(int x, int y) {
    if (x == y) {
      return n - x;
    }
    x = pos[x];
    y = pos[y];
    if (x > y) {
      swap(x, y);
    }
    --y;
    int k = zeros[y - x + 1];
    return min(rmq[k][x], rmq[k][y - (1 << k) + 1]);
  }
};

const int base = 2333;
const int md0 = 1e9 + 7;
const int md1 = 1e9 + 9;

struct hash_t {
  int hash0, hash1;

  hash_t(int hash0 = 0, int hash1 = 0): hash0(hash0), hash1(hash1) {
  }

  hash_t operator + (const int &x) const {
    return hash_t((hash0 + x) % md0, (hash1 + x) % md1);
  };

  hash_t operator * (const int &x) const {
    return hash_t((long long)hash0 * x % md0, (long long)hash1 * x % md1);
  }

  hash_t operator + (const hash_t &x) const {
    return hash_t((hash0 + x.hash0) % md0, (hash1 + x.hash1) % md1);
  };

  hash_t operator - (const hash_t &x) const {
    return hash_t((hash0 + md0 - x.hash0) % md0, (hash1 + md1 - x.hash1) % md1);
  };

  hash_t operator * (const hash_t &x) const {
    return hash_t((long long)hash0 * x.hash0 % md0, (long long)hash1 * x.hash1 % md1);
  }

  inline long long get() {
    return (long long)hash0 * md1 + hash1;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(0);
  cin.tie(0);
  int tt;
  cin >> tt;
  while (tt--) {
    string s;
    cin >> s;
    int n = s.length();
    vector<int> sa = suffix_array(s, n, 256);
    vector<int> lcp = build_lcp(s, n, sa);
    lcp_query_t lcp_query(sa, lcp);
    reverse(s.begin(), s.end());
    vector<int> rev_sa = suffix_array(s, n, 256);
    vector<int> rev_lcp = build_lcp(s, n, rev_sa);
    lcp_query_t lcs_query(rev_sa, rev_lcp);
    reverse(s.begin(), s.end());
    vector<int> sum_inv(n + 1);
    for (int i = 1; i <= n; ++i) {
      sum_inv[i] = sum_inv[i - 1] + n / i - 1;
    }
    vector<bool> covered(sum_inv[n] + 1);
    vector<hash_t> hash(n + 1), power(n + 1);
    power[0] = hash_t(1, 1);
    for (int i = 0; i < n; ++i) {
      hash[i + 1] = hash[i] * base + s[i];
      power[i + 1] = power[i] * base;
    }
    unordered_map<long long, int> times;
    auto get = [&](int l, int r) {
      return (hash[r] - hash[l] * power[r - l]).get();
    };
    auto add = [&](int l, int r, int t) {
      long long h = get(l, r);
      times[h] = max(times[h], t);
    };
    for (int i = 1; i <= n; ++i) {
      int l = -1, r = -1;
      for (int j = i - 1; j + i < n; j += i) {
        if (j > r) {
          int lcp = lcp_query.get_lcp(j, j + i);
          int lcs = lcs_query.get_lcp(n - j - 1, n - j - i - 1);
          if (lcp + lcs - 1 < i) {
            continue;
          }
          l = j - lcs + 1;
          r = j + lcp - 1;
          if (covered[sum_inv[i - 1] + (j + 1) / i]) {
            continue;
          }
          for (int x = i * 2; l + x * 2 - 1 <= r + i; x += i) {
            covered[sum_inv[x - 1] + (l + x) / x] = true;
          }
          for (int k = l; k <= r - i + 1 && k < l + i; ++k) {
            add(k, k + i, (r - k + 1) / i);
          }
        }
      }
    }
    long long answer = (long long)n * (n + 1) / 2;
    for (int i = 0; i < n - 1; ++i) {
      answer -= lcp[i];
    }
    for (auto p : times) {
      answer -= p.second;
    }
    printf("%lld\n", answer);
  }
  return 0;
}

Rikka with Intersections of Paths

点减边。

#include 

using namespace std;

const int N = 345678;
const int md = 1e9 + 7;

int n, m, q, answer, f[N], g[N], fact[N], size[N], ifact[N], depth[N], belong[N], parent[N];
vector<int> adj[N];

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (long long)x * y % md;
}

inline int binom(int x, int y) {
  return x < y ? 0 : mul(fact[x], mul(ifact[y], ifact[x - y]));
}

void dfs(int x) {
  size[x] = 1;
  for (auto y : adj[x]) {
    if (y != parent[x]) {
      depth[y] = depth[x] + 1;
      parent[y] = x;
      dfs(y);
      size[x] += size[y];
    }
  }
}

void hld(int x, int c) {
  belong[x] = c;
  int son = -1;
  for (auto y : adj[x]) {
    if (y != parent[x] && (!~son || size[y] > size[son])) {
      son = y;
    }
  }
  if (~son) {
    hld(son, c);
    for (auto y : adj[x]) {
      if (y != parent[x] && y != son) {
        hld(y, y);
      }
    }
  }
}

void solve(int x) {
  for (auto y : adj[x]) {
    if (y != parent[x]) {
      solve(y);
      f[x] += f[y];
      g[x] += g[y];
    }
  }
  add(answer, binom(f[x], q));
  sub(answer, binom(g[x], q));
}

inline int lca(int x, int y) {
  while (belong[x] != belong[y]) {
    if (depth[belong[x]] >= depth[belong[y]]) {
      x = parent[belong[x]];
    } else {
      y = parent[belong[y]];
    }
  }
  return depth[x] < depth[y] ? x : y;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d %d %d", &n, &m, &q);
    fact[0] = fact[1] = ifact[0] = ifact[1] = 1;
    for (int i = 2; i <= m; ++i) {
      fact[i] = mul(fact[i - 1], i);
      ifact[i] = mul(md - md / i, ifact[md % i]);
    }
    for (int i = 2; i <= m; ++i) {
      ifact[i] = mul(ifact[i - 1], ifact[i]);
    }
    for (int i = 0; i < n; ++i) {
      adj[i].clear();
      f[i] = g[i] = 0;
    }
    for (int i = 0; i < n - 1; ++i) {
      int x, y;
      scanf("%d %d", &x, &y);
      --x;
      --y;
      adj[x].push_back(y);
      adj[y].push_back(x);
    }
    parent[0] = -1;
    dfs(0);
    hld(0, 0);
    for (int i = 0; i < m; ++i) {
      int x, y;
      scanf("%d %d", &x, &y);
      --x;
      --y;
      int z = lca(x, y);
      ++f[x];
      ++f[y];
      --f[z];
      if (z) {
        --f[parent[z]];
      }
      ++g[x];
      ++g[y];
      g[z] -= 2;
    }
    answer = 0;
    solve(0);
    printf("%d\n", answer);
  }
  return 0;
}

Rikka with A Long Colour Palette

将线段按照左端点排序,维护每个颜色的右端点,贪心取右端点最小的往右移动即可。注意特判 n < k n<k n<k ,不然复杂度是错的。

#include 

using namespace std;

const int N = 234567;

pair<pair<int, int>, int> a[N], events[N << 1];
int n, m, has[N], color[N], answer[N];

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; ++i) {
      scanf("%d %d", &a[i].first.first, &a[i].first.second);
      a[i].second = i;
    }
    if (n < m) {
      puts("0");
      for (int i = 0; i < n; ++i) {
        printf("1%c", i == n - 1 ? '\n' : ' ');
      }
      continue;
    }
    sort(a, a + n);
    priority_queue<pair<int, int>> q;
    for (int i = 0; i < m; ++i) {
      q.push(make_pair(0, i));
    }
    for (int i = 0; i < n; ++i) {
      int x = q.top().second;
      q.pop();
      answer[a[i].second] = color[i] = x;
      q.emplace(-a[i].first.second, x);
    }
    int total = 0;
    for (int i = 0; i < n; ++i) {
      events[total++] = make_pair(make_pair(a[i].first.first, color[i]), 1);
      events[total++] = make_pair(make_pair(a[i].first.second, color[i]), -1);
    }
    sort(events, events + total);
    int result = 0, current = 0;
    for (int i = 0; i < total; ++i) {
      if (has[events[i].first.second]) {
        --current;
      }
      has[events[i].first.second] += events[i].second;
      if (has[events[i].first.second]) {
        ++current;
      }
      if (current == m) {
        result += events[i + 1].first.first - events[i].first.first;
      }
    }
    printf("%d\n", result);
    for (int i = 0; i < n; ++i) {
      printf("%d%c", answer[i] + 1, i == n - 1 ? '\n' : ' ');
    }
  }
  return 0;
}

Rikka with Sorting Networks

almost sorted 的序列只有 n 2 n^2 n2 个,枚举最后序列的形态,倒着搜索排序网络即可。

#include 

using namespace std;

const int N = 56;

int n, m, md, answer, a[N], from[N], to[N];

void dfs(int x, int sign) {
  if (!~x) {
    answer += sign;
  } else if (a[from[x]] < a[to[x]]) {
    dfs(x - 1, sign);
    swap(a[from[x]], a[to[x]]);
    dfs(x - 1, sign);
    swap(a[from[x]], a[to[x]]);
  }
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d %d %d", &n, &m, &md);
    for (int i = 0; i < m; ++i) {
      scanf("%d %d", &from[i], &to[i]);
      --from[i];
      --to[i];
    }
    answer = 0;
    for (int i = 0; i < n; ++i) {
      a[i] = i;
    }
    dfs(m - 1, 1);
    for (int i = 0; i < n - 1; ++i) {
      swap(a[i], a[i + 1]);
      dfs(m - 1, -1);
      swap(a[i], a[i + 1]);
    }
    for (int take = 0; take < n; ++take) {
      for (int i = 0; i < n; ++i) {
        if (i != take) {
          int current = 0;
          for (int j = 0; j < n; ++j) {
            if (j == i) {
              a[j] = take;
            } else {
              if (current == take) {
                ++current;
              }
              a[j] = current++;
            }
          }
          dfs(m - 1, 1);
        }
      }
    }
    printf("%d\n", answer);
  }
  return 0;
}

Rikka with An Unnamed Temple

随便求出一个拓扑序,求出前缀和后缀的DP,那么删去一个点就是要某一步从拓扑序上跨过它,线段树打标记即可。注意如果拓扑序在 1 1 1 之前或者 n n n 之后要特判。

#include 

using namespace std;

const int N = 123456;
const int M = 123;
const int md = 1e9 + 7;

int n, m, s, t, pos[N], order[N], value[N], degree[N], weight[N];
vector<int> adj[N], rev[N];

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (long long)x * y % md;
}

struct node_t {
  long long value;
  int ways;

  node_t(long long value = -1, int ways = 0): value(value), ways(ways) {
  }
    
  void apply(long long v, int w) {
    if (value < v) {
      value = v;
      ways = w;
    } else if (value == v) {
      add(ways, w);
    }
  }
} answer[N], from[N][M], to[N][M];

class segtree_t {
 public:
  vector<node_t> tree;
  int n;

  segtree_t(int n): n(n) {
    tree.resize((n << 1) - 1);
  }

  inline void push(int x, int z) {
    tree[x + 1].apply(tree[x].value, tree[x].ways);
    tree[z].apply(tree[x].value, tree[x].ways);
  }

  template<typename... T> void modify(int x, int l, int r, int ql, int qr, const T&... v) {
    if (l == ql && r == qr) {
      tree[x].apply(v...);
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      if (qr <= y) {
        modify(x + 1, l, y, ql, qr, v...);
      } else if (ql > y) {
        modify(z, y + 1, r, ql, qr, v...);
      } else {
        modify(x + 1, l, y, ql, y, v...);
        modify(z, y + 1, r, y + 1, qr, v...);
      }
    }
  }

  template<typename... T> void modify(int l, int r, const T&... v) {
    modify(0, 0, n - 1, l, r, v...);
  }

  void query(int x, int l, int r, vector<node_t> &a) {
    if (l == r) {
      a[l] = tree[x];
    } else {
      int y = l + r >> 1, z = x + (y - l + 1 << 1);
      push(x, z);
      query(x + 1, l, y, a);
      query(z, y + 1, r, a);
    }
  }

  vector<node_t> query() {
    vector<node_t> a(n);
    query(0, 0, n - 1, a);
    return a;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; ++i) {
      scanf("%d %d", &weight[i], &value[i]);
      adj[i].clear();
      rev[i].clear();
    }
    for (int i = 0; i < m; ++i) {
      int x, y;
      scanf("%d %d", &x, &y);
      --x;
      --y;
      adj[x].push_back(y);
      rev[y].push_back(x);
      ++degree[y];
    }
    int top = 0;
    for (int i = 0; i < n; ++i) {
      if (!degree[i]) {
        order[top++] = i;
      }
    }
    for (int i = 0; i < n; ++i) {
      int x = order[i];
      for (auto y : adj[x]) {
        if (!--degree[y]) {
          order[top++] = y;
        }
      }
    }
    scanf("%d %d", &s, &t);
    for (int i = 0; i < n; ++i) {
      int x = order[i];
      for (int j = 0; j < s; ++j) {
        from[x][j] = node_t();
      }
      if (!x) {
        from[x][weight[x] % s] = node_t(value[x], 1);
      }
      for (auto y : rev[x]) {
        for (int j = 0; j < s; ++j) {
          if (~from[y][j].value) {
            from[x][(j + weight[x]) % s].apply(from[y][j].value + value[x], from[y][j].ways);
          }
        }
      }
    }
    for (int i = n - 1; ~i; --i) {
      int x = order[i];
      for (int j = 0; j < s; ++j) {
        to[x][j] = node_t();
      }
      if (x == n - 1) {
        to[x][weight[x] % s] = node_t(value[x], 1);
      }
      for (auto y : adj[x]) {
        for (int j = 0; j < s; ++j) {
          if (~to[y][j].value) {
            to[x][(j + weight[x]) % s].apply(to[y][j].value + value[x], to[y][j].ways);
          }
        }
      }
    }
    for (int i = 0; i < n; ++i) {
      pos[order[i]] = i;
    }
    segtree_t segtree(n);
    for (int x = 0; x < n; ++x) {
      for (auto y : adj[x]) {
        if (pos[x] + 1 <= pos[y] - 1) {
          node_t best;
          for (int i = 0; i < s; ++i) {
            if (~from[x][i].value) {
              int j = (t + s - i) % s;
              if (~to[y][j].value) {
                best.apply(from[x][i].value + to[y][j].value, mul(from[x][i].ways, to[y][j].ways));
              }
            }
          }
          if (~best.value) {
            segtree.modify(pos[x] + 1, pos[y] - 1, best.value, best.ways);
          }
        }
      }
    }
    if (pos[0]) {
      segtree.modify(0, pos[0] - 1, from[n - 1][t].value, from[n - 1][t].ways);
    }
    if (pos[n - 1] < n - 1) {
      segtree.modify(pos[n - 1] + 1, n - 1, from[n - 1][t].value, from[n - 1][t].ways);
    }
    vector<node_t> answer = segtree.query();
    for (int i = 0; i < n; ++i) {
      if (~answer[pos[i]].value) {
        printf("%lld %d\n", answer[pos[i]].value, answer[pos[i]].ways);
      } else {
        puts("-1");
      }
    }
  }
  return 0;
}

Rikka with Ants

模拟。

#include 

using namespace std;

const int N = 56;

int n, from[2], to[2], a[N], visit[N];
pair<int, int> value[2][2];
double p[2];

pair<int, int> solve() {
  for (int i = 0; i < n; ++i) {
    visit[i] = 0;
  }
  for (int i = 0; i < 2; ++i) {
    for (int j = from[i]; j != to[i]; j = (j + 1) % n) {
      visit[j] |= 1 << i;
    }
  }
  pair<int, int> result;
  for (int i = 0; i < n; ++i) {
    if (visit[i] == 3) {
      result.first += a[i] * 3;
      result.second += a[i] * 3;
    } else if (visit[i] == 1) {
      result.first += a[i];
    } else if (visit[i] == 2) {
      result.second += a[i];
    }
  }
  return result;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
      scanf("%d", &a[i]);
    }
    for (int i = 0; i < 2; ++i) {
      scanf("%d %d", &from[i], &to[i]);
      --from[i];
      --to[i];
    }
    for (int i = 0; i < 2; ++i) {
      for (int j = 0; j < 2; ++j) {
        value[i][j] = solve();
        swap(from[1], to[1]);
      }
      swap(from[0], to[0]);
    }
    if (value[0][0].first <= value[1][0].first && value[0][1].first <= value[1][1].first) {
      if (value[0][0].second <= value[0][1].second) {
        printf("%d %d\n", value[0][0].first, value[0][0].second);
      } else {
        printf("%d %d\n", value[0][1].first, value[0][1].second);
      }
      continue;
    }
    if (value[0][0].first >= value[1][0].first && value[0][1].first >= value[1][1].first) {
      if (value[1][0].second <= value[1][1].second) {
        printf("%d %d\n", value[1][0].first, value[1][0].second);
      } else {
        printf("%d %d\n", value[1][1].first, value[1][1].second);
      }
      continue;
    }
    if (value[0][0].second <= value[0][1].second && value[1][0].second <= value[1][1].second) {
      if (value[0][0].first <= value[1][0].first) {
        printf("%d %d\n", value[0][0].first, value[0][0].second);
      } else {
        printf("%d %d\n", value[1][0].first, value[1][0].second);
      }
      continue;
    }
    if (value[0][0].second >= value[0][1].second && value[1][0].second >= value[1][1].second) {
      if (value[0][1].first <= value[1][1].first) {
        printf("%d %d\n", value[0][1].first, value[0][1].second);
      } else {
        printf("%d %d\n", value[1][1].first, value[1][1].second);
      }
      continue;
    }
    double p0 = (double)(value[1][1].second - value[1][0].second) / (value[0][0].second + value[1][1].second - value[0][1].second - value[1][0].second), q0 = 1 - p0;
    double p1 = (double)(value[1][1].first - value[0][1].first) / (value[0][0].first + value[1][1].first - value[0][1].first - value[1][0].first), q1 = 1 - p1;
    double w0 = p0 * p1 * value[0][0].first + p0 * q1 * value[0][1].first + q0 * p1 * value[1][0].first + q0 * q1 * value[1][1].first;
    double w1 = p0 * p1 * value[0][0].second + p0 * q1 * value[0][1].second + q0 * p1 * value[1][0].second + q0 * q1 * value[1][1].second;
    printf("%.10lf %.10lf\n", w0, w1);
  }
  return 0;
}

Rikka with Grid Graphs

状压记录闭包,状态不多。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  {
    string foo;
    getline(cin, foo);
    stringstream ss;
    ss << foo;
    ss >> tt;
  }
  while (tt--) {
    int n, m;
    {
      string foo;
      getline(cin, foo);
      stringstream ss;
      ss << foo;
      ss >> n >> m;
    }
    unordered_map<long long, long long> dp;
    dp[0] = 1;
    for (int row = 0; row < n * 2 - 1; ++row) {
      string foo;
      getline(cin, foo);
      unordered_map<long long, long long> new_dp;
      if (row & 1) {
        vector<int> down;
        for (int j = 0; j < m && j << 1 < foo.length(); ++j) {
          if (foo[j << 1] == '|') {
            down.push_back(j);
          }
        }
        for (auto p : dp) {
          for (int s = 0; s < 1 << down.size(); ++s) {
            long long mask = 0;
            for (int i = 0; i < down.size(); ++i) {
              if (s >> i & 1) {
                for (int j = 0; j < down.size(); ++j) {
                  if (!(s >> j & 1)) {
                    if (p.first >> down[i] * m + down[j] & 1) {
                      mask |= 1ll << down[i] * m + down[j];
                    }
                  }
                }
              }
            }
            new_dp[mask] += p.second;
          }
        }
      } else {
        vector<int> right;
        for (int j = 0; j < m - 1 && (j << 1 | 1) < foo.length(); ++j) {
          if (foo[j << 1 | 1] == '-') {
            right.push_back(j);
          }
        }
        for (auto p : dp) {
          for (int s = 0; s < 1 << right.size(); ++s) {
            long long mask = p.first;
            for (int i = 0; i < right.size(); ++i) {
              if (s >> i & 1) {
                mask |= 1ll << right[i] * m + right[i] + 1;
              } else {
                mask |= 1ll << right[i] * m + right[i] + m;
              }
            }
            for (int k = 0; k < m; ++k) {
              for (int i = 0; i < m; ++i) {
                if (mask >> i * m + k & 1) {
                  for (int j = 0; j < m; ++j) {
                    if (mask >> k * m + j & 1) {
                      mask |= 1ll << i * m + j;
                    }
                  }
                }
              }
            }
            bool ok = true;
            for (int i = 0; i < m && ok; ++i) {
              for (int j = 0; j < m && ok; ++j) {
                if ((mask >> i * m + j & 1) && (mask >> j * m + i & 1)) {
                  ok = false;
                }
              }
            }
            if (ok) {
              new_dp[mask] += p.second;
            }
          }
        }
      }
      swap(dp, new_dp);
    }
    long long answer = 0;
    for (auto p : dp) {
      answer += p.second;
    }
    printf("%lld\n", answer);
  }
  return 0;
}

Rikka with Illuminations

求出每个点投影的区间,然后枚举起点贪心覆盖即可。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    int n, m;
    scanf("%d %d", &n, &m);
    vector<pair<int, int>> p(n);
    for (int i = 0; i < n; ++i) {
      scanf("%d %d", &p[i].first, &p[i].second);
    }
    vector<int> go(n), id(n, -1);
    for (int i = 0; i < m; ++i) {
      pair<int, int> q;
      scanf("%d %d", &q.first, &q.second);
      int l = 0, r = 0;
      for (int j = 1; j < n; ++j) {
        if ((long long)(p[r].first - q.first) * (p[j].second - q.second) < (long long)(p[j].first - q.first) * (p[r].second - q.second)) {
          r = j;
        }
        if ((long long)(p[l].first - q.first) * (p[j].second - q.second) > (long long)(p[j].first - q.first) * (p[l].second - q.second)) {
          l = j;
        }
      }
      for (int j = l; j != r; j = (j + 1) % n) {
        if (go[j] < (r - j + n) % n) {
          go[j] = (r - j + n) % n;
          id[j] = i;
        }
      }
    }
    if (!*min_element(go.begin(), go.end())) {
      puts("-1");
      continue;
    }
    int answer = n + 1, start = -1;
    for (int i = 0; i < n; ++i) {
      int j = i, k = 0;
      while (j < i + n) {
        j += go[j % n];
        ++k;
      }
      if (answer > k) {
        answer = k;
        start = i;
      }
    }
    printf("%d\n", answer);
    for (int i = 0; i < answer; ++i) {
      printf("%d%c", id[start] + 1, i == answer - 1 ? '\n' : ' ');
      start = (start + go[start]) % n;
    }
  }
  return 0;
}

你可能感兴趣的:(CodeForces Gym 102012 简要题解)