提交记录 120210


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_cc_v41_agg1 1009b. 测测你的三维数点3 Accepted 100 336.85 us 416 KB C++17 14.48 KB
提交时间 评测时间
2026-10-02 18:05:56 2026-10-02 18:05:58
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #120158 <https://duck.ac/submission/120158>
//     (0.324216 ms = 本题当刻 T)。用途:**两处改动逐字抄自该公开提交**(公开提交,剥注释逐行 diff 得到):
//       (a) pragma:`optimize("O3")` → `optimize("O3","unroll-loops","rename-registers","align-loops=32")`;
//       (b) `scanv()` 的位置掩码:由"循环携减 `rem`"改为"编译期绝对车道 `lane+16r`"(去掉循环依赖链)。
//     该件与本件不构成同源重复件:本件**不含**它的第三处改动 (c)(x 序打包与散列合并、去 `ordx`)——
//     见 [2] 的判题机配对读数,(c) 是负的。
// [2] duck.ac 用户 saffah_codex_6s_agg2,提交 #107847 <https://duck.ac/submission/107847>(0.329009 ms)
//     = 我方 #106331 正文 + 仅 pragma 一行(本席逐行 diff 核实);用途:独立复核 (a) 的符号与量级,
//     并作为 (c) 的对照:**#107847(无 (c))0.329009 vs #120152(有 (c))0.330190 ⇒ (c) = +1.18 µs(−0.36%)**
//     ⇒ 本件保留 `ordx`,不抄 (c)。
// [3] 本账号 saffah_cc_v41_agg1,提交 #106331 <https://duck.ac/submission/106331>(0.331488 ms)
//     —— 本件基底正文(`work/x14b_bscan_prod.cpp`)。
// [4] BRIEF §2.18.349(抄对手:取件→剥注释→逐行 diff→逐字抄)/ §2.18.348(姊妹移植:见思路末条)。
// ======================
// ===== 思路 =====
// 本件 = **对手 #120158 的两把刀逐字搬回** + **本席两处逐位等价改写**(四处均为逐位等价,
// 闸门 = `work/e9x_gate.py` 7/7 mode 与基底 `x14b_bscan_prod.cpp` 逐位相同)。
// [K9X-PRAGMA](抄 [1](a))只改一行 pragma(调度口径,数据与运算不变);判题机实测:我方 #106331
//   0.331488 → 同正文 + 该 pragma 的 #107847 **0.329009 = −2.48 µs(−0.75%)** ✓
// [K9X-LANEFOLD](抄 [1](b))`scanv()` 的 16 车道位置掩码原为循环携减:
//     `rem = off; for r { c = cmpgt_epi16(t,p) & cmpgt_epi16(rem, lane); rem -= 16; }`
//   改为编译期绝对车道:`cmpgt_epi16(rem, lane + 16*r)`(`rem` 恒 = off,去掉循环依赖链)。
//   **逐位等价**:第 r 轮旧判据 `off-16r > lane` ⇔ 新判据 `off > lane+16r`;off∈[0,128)、lane+16r ≤ 127
//   ⇒ i16 无溢出;旧式 rem 可为负、新式恒 ≥0,signed `cmpgt` 在两者上同为假 ⇒ 逐车道结果相同 ✓。
//   判题机实测(对手两件、单变量配对):**#120152 0.330190 → #120158 0.324216 = −5.97 µs(−1.81%)** ✓
// [K9X-SENT](本席)分组边界判定去 2 条/元素指令:原 `int q=p+1; … if (e>p && (m&0x3FFF)!=xv){q=e;break;} … q=e+1;`
//   改为 `int q=n; … if ((m&0x3FFF)!=xv){q=e;break;} …`(删 `e>p` 与 `q=e+1`)。
//   **等价性**:(i) e==p 轮 `m==QA[p]` ⇒ `(m&0x3FFF)==xv` 恒真 ⇒ 旧 `e>p` 守卫该轮恒"不跳出",删之无差;
//   (ii) 循环自然走完(e==n)时终点须为 n ⇒ 用初始化 `q=n` 取代每轮的 `q=e+1`。唯一消费点 = pass 2 的
//   `for(e=p;e<q;e++)` 与 `p=q`,取值逐位不变 ✓(对任意 n 成立,不需哨兵、不触碰 0x3FFF 夹逼)。
// [K9X-O16](本席)`ordx[]` u32 → u16:**少触 20 KB(5 页)+ 打包趟的写/读各从 40 KB 降到 20 KB**。
//   不变量:现有 bail 条件 `S>320 || G>640` 已把支持域限制在 n ≤ 320*BB = 40960 < 65536 ⇒ 下标必容于 u16
//   (本席另补显式守卫 `n > 60000` 以自证该不变量,由前两项已蕴含、不改变任何 n 的行为)。
//   **动机 = 缺页账**:官方计时 = `clock()` 进程 CPU 时间(含缺页系统时间);本题在册首触页价
//   **872 cyc/页 = 0.242 µs/页**(本文件第九轮判题机标定表)⇒ 5 页 ≈ 1.2 µs。
// 【为什么本件**不**抄对手的第三处 (c)】判题机单变量配对([2]):(c)(x 序打包与散列合并、去 `ordx`)
//   = **+1.18 µs(−0.36%)**;机理与在册 `[K9W2-FUSE]`/`[K9W2-FUSE2]` 一致(散布写 `QA[e]/QB[e]` 的 RFO
//   大于省下的两趟遍历),且本席本机复测其别名形态时另发现就地前缀在 `const u16*` 形参下会被优化器
//   判为非别名(`work/k9x_tmp/pfx_test.cpp` 与闸门读数为证)⇒ 该族不做。
// 【预期】mine 0.331488(#106331)− 2.48(pragma)− 5.97(lanefold)− ~0.5(sent)− ~1.5(o16)
//   ≈ **0.3210 ms**;严支线 `0.99*T + 1µs`(T = 0.324216,[1])= **0.321974** ⇒ 本件瞄准该线。
// ======================
// [k9x_p6] P6 = P5 + O16(ordx u32->u16,少触 20 KB)
#include <string.h>
#include <immintrin.h>
#pragma GCC push_options
#pragma GCC optimize("O3","unroll-loops","rename-registers","align-loops=32")
#pragma GCC target("avx2,popcnt,tune=skylake")
typedef unsigned u32;
typedef unsigned short u16;
typedef unsigned long long u64;
typedef unsigned char u8;

#define AVX2 __attribute__((target("avx2")))
#define BB 128
#define XB 288   /* [e9x 2nd seat] XB 256->288, ported from rival #106226 (byte-for-byte his value) */
#define BLKIDX(r) ((int)((r) / BB))
#define BLOFF(v)  ((int)((v) % BB))
#define BLK0(f)   ((f) * BB)
#ifndef MAXN
#define MAXN 100005
#endif
#define MAXG 640
#define SENTB 0x7F7F

static u16 H[MAXG * 320];
static u16 CP[MAXG * 320];
static u16 YZ[MAXN + 32];
static u8 ZY[MAXN + 32];
static u8 recY[XB + 32], recZ[XB + 32];
static signed char laneB[BB];
static u16 cnt[MAXN + 2], stv[MAXN + 2], curs[MAXN + 2];
static u16 ordx[MAXN + 2];   /* [K9X-O16] u32->u16:n<=40960(现有 bail 条件)< 65536 */
static u64 QA[MAXN + 2];
static u32 QB[MAXN + 2];
static u64 meta[MAXN + 2];

/* [e9x] 16-lane u16 exclusive scan: stv[] and curs[] both take the exclusive prefix.
   Sums reach n=10000 < 65536 so u16 is exact; bit-identical to the scalar serial form. */
AVX2 static inline void pfx16(const u16 *c, u16 *a1, u16 *a2, int n) {
  const __m256i b7w = _mm256_setr_epi8(14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,
                                       14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15);
  __m256i carry = _mm256_setzero_si256();
  int v = 0;
  for (; v + 16 <= n + 1; v += 16) {
    __m256i o = _mm256_loadu_si256((const __m256i *)(c + v));
    __m256i x = o;
    x = _mm256_add_epi16(x, _mm256_slli_si256(x, 2));
    x = _mm256_add_epi16(x, _mm256_slli_si256(x, 4));
    x = _mm256_add_epi16(x, _mm256_slli_si256(x, 8));
    x = _mm256_add_epi16(x, _mm256_shuffle_epi8(
        _mm256_permute2x128_si256(x, x, 0x08), b7w));
    __m256i acc = _mm256_add_epi16(x, carry);
    __m256i ex = _mm256_sub_epi16(acc, o);
    _mm256_storeu_si256((__m256i *)(a1 + v), ex);
    _mm256_storeu_si256((__m256i *)(a2 + v), ex);
    carry = _mm256_shuffle_epi8(_mm256_permute2x128_si256(acc, acc, 0x11), b7w);
  }
  u32 a = (v == 0) ? 0u : (u32)_mm256_extract_epi16(carry, 0);
  for (; v <= n; v++) { u32 cc = c[v]; a1[v] = (u16)a; a2[v] = (u16)a; a += cc; }
}
static u16 maskTab[17][16] __attribute__((aligned(32)));
static int gS;
static u16 ZERO_CP_ROW[320] __attribute__((aligned(32)));

AVX2 static inline __m256i ldu256(const void *p) { return _mm256_loadu_si256((const __m256i *)p); }
AVX2 static inline void stu256(void *p, __m256i v) { _mm256_storeu_si256((__m256i *)p, v); }
AVX2 static inline u32 hsum8(__m256i s) {
  __m128i lo = _mm256_castsi256_si128(s), hi = _mm256_extracti128_si256(s, 1);
  __m128i t = _mm_add_epi32(lo, hi);
  t = _mm_add_epi32(t, _mm_shuffle_epi32(t, _MM_SHUFFLE(1, 0, 3, 2)));
  t = _mm_add_epi32(t, _mm_shuffle_epi32(t, _MM_SHUFFLE(2, 3, 0, 1)));
  return (u32)_mm_cvtsi128_si32(t);
}

AVX2 static inline __m256i scanv(const u16 *v, int off, int thr) {
  /* FIXED-TRIP-COUNT: always scan all BB/16 = 16 vectors, masking the lanes
     at/after `off` with a running "remaining" vector.  Bit-identical to the
     data-dependent form above, but the loop-exit branch is always predictable. */
  const __m256i t = _mm256_set1_epi16((short)thr);
  const __m256i lane = _mm256_setr_epi16(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
  __m256i rem = _mm256_set1_epi16((short)off);
  __m256i acc = _mm256_setzero_si256();
  const u16 *p = v;
  for (int r = 0; r < (BB >> 4); r++, p += 16) {
    __m256i c = _mm256_and_si256(_mm256_cmpgt_epi16(t, ldu256(p)),
                                 _mm256_cmpgt_epi16(rem, _mm256_add_epi16(lane, _mm256_set1_epi16((short)(16 * r)))));
    acc = _mm256_sub_epi16(acc, c);
  }
  return acc;
}

/* u8 block-index scan: `value < thr` over 32-byte vectors.  thr is a block index
   (<= 78) and the sentinel is 0x7F, so signed vpcmpgtb is exact for the value
   test.  The positional cut is unsigned -- (off ^ 0x80) >signed (lane ^ 0x80) --
   so off may range over [0,256); laneB[] holds (32r + lane) ^ 0x80 as a signed
   byte and is built once per call.  The accumulator counts UP. */
AVX2 static inline __m256i scanb(const u8 *v, int off, int thr) {
  const __m256i t = _mm256_set1_epi8((char)thr);
  const __m256i k = _mm256_set1_epi8((char)(off ^ 0x80));
  __m256i acc = _mm256_setzero_si256();
  const u8 *p = v;
  for (int r = 0; r < (BB >> 5); r++, p += 32) {
    __m256i c = _mm256_and_si256(_mm256_cmpgt_epi8(t, ldu256(p)),
                                 _mm256_cmpgt_epi8(k, ldu256(laneB + 32 * r)));
    acc = _mm256_sub_epi8(acc, c);
  }
  return acc;
}

/* ring twin: no positional mask needed -- padrec() keeps the tail at 0x7F and
   0x7F fails both tests (fy <= 78 < 127). */
AVX2 static inline __m256i scanbrec(int fy, int fz, int nrec) {
  const __m256i ty = _mm256_set1_epi8((char)fy);
  const __m256i tz = _mm256_set1_epi8((char)fz);
  __m256i acc = _mm256_setzero_si256();
  const u8 *py = recY, *pz = recZ;
  for (int r = 0; r < 3; r++, py += 32, pz += 32)
    acc = _mm256_sub_epi8(acc, _mm256_and_si256(_mm256_cmpgt_epi8(ty, ldu256(py)),
                                               _mm256_cmpgt_epi8(tz, ldu256(pz))));
  if (nrec > 96)
    for (int r = 3; r < 6; r++, py += 32, pz += 32)
      acc = _mm256_sub_epi8(acc, _mm256_and_si256(_mm256_cmpgt_epi8(ty, ldu256(py)),
                                                 _mm256_cmpgt_epi8(tz, ldu256(pz))));
  if (nrec > 192)
    for (int r = 6; r < 9; r++, py += 32, pz += 32)
      acc = _mm256_sub_epi8(acc, _mm256_and_si256(_mm256_cmpgt_epi8(ty, ldu256(py)),
                                                 _mm256_cmpgt_epi8(tz, ldu256(pz))));
  return acc;
}

AVX2 static inline void padrec(void) {
  for (int k = 0; k < XB + 16; k++) { recY[k] = 0x7F; recZ[k] = 0x7F; }
}

template <int TS> AVX2 static void rebuild_cp(int G) {
  const int S = (TS > 0) ? TS : gS;
  const __m256i bcastLast = _mm256_setr_epi8(14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,
                                             14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15);
  int fy = 0;
  for (; fy + 1 < G; fy += 2) {
    const u16 *h0 = H + (size_t)fy * S, *h1 = h0 + S;
    u16 *c0 = CP + (size_t)fy * S, *c1 = c0 + S;
    const u16 *pv = fy ? CP + (size_t)(fy - 1) * S : ZERO_CP_ROW;
    __m256i k0 = _mm256_setzero_si256(), k1 = _mm256_setzero_si256();
    for (int j = 0; j < S; j += 16) {
      __m256i v0 = ldu256(h0 + j), v1 = ldu256(h1 + j);
      v0 = _mm256_add_epi16(v0, _mm256_slli_si256(v0, 2));
      v1 = _mm256_add_epi16(v1, _mm256_slli_si256(v1, 2));
      v0 = _mm256_add_epi16(v0, _mm256_slli_si256(v0, 4));
      v1 = _mm256_add_epi16(v1, _mm256_slli_si256(v1, 4));
      v0 = _mm256_add_epi16(v0, _mm256_slli_si256(v0, 8));
      v1 = _mm256_add_epi16(v1, _mm256_slli_si256(v1, 8));
      v0 = _mm256_add_epi16(v0, _mm256_shuffle_epi8(_mm256_permute2x128_si256(v0, v0, 0x08), bcastLast));
      v1 = _mm256_add_epi16(v1, _mm256_shuffle_epi8(_mm256_permute2x128_si256(v1, v1, 0x08), bcastLast));
      __m256i r0 = _mm256_add_epi16(v0, k0), r1 = _mm256_add_epi16(v1, k1);
      k0 = _mm256_shuffle_epi8(_mm256_permute2x128_si256(r0, r0, 0x11), bcastLast);
      k1 = _mm256_shuffle_epi8(_mm256_permute2x128_si256(r1, r1, 0x11), bcastLast);
      __m256i d0 = _mm256_add_epi16(r0, ldu256(pv + j));
      stu256(c0 + j, d0);
      stu256(c1 + j, _mm256_add_epi16(r1, d0));
    }
  }
  for (; fy < G; fy++) {
    const u16 *h = H + (size_t)fy * S;
    u16 *c = CP + (size_t)fy * S;
    const u16 *pv = fy ? CP + (size_t)(fy - 1) * S : ZERO_CP_ROW;
    __m256i k = _mm256_setzero_si256();
    for (int j = 0; j < S; j += 16) {
      __m256i v = ldu256(h + j);
      v = _mm256_add_epi16(v, _mm256_slli_si256(v, 2));
      v = _mm256_add_epi16(v, _mm256_slli_si256(v, 4));
      v = _mm256_add_epi16(v, _mm256_slli_si256(v, 8));
      v = _mm256_add_epi16(v, _mm256_shuffle_epi8(_mm256_permute2x128_si256(v, v, 0x08), bcastLast));
      __m256i r = _mm256_add_epi16(v, k);
      k = _mm256_shuffle_epi8(_mm256_permute2x128_si256(r, r, 0x11), bcastLast);
      stu256(c + j, _mm256_add_epi16(r, ldu256(pv + j)));
    }
  }
}


template <int CG, int CS> static void engine_t(int n, const unsigned *x, const unsigned *y, const unsigned *z, unsigned *out) {
  constexpr int TSC = CS;
  if (n <= 1) { if (n == 1) out[0] = 0; return; }
  const int G = (CG > 0) ? CG : ((n + BB - 1) / BB);
  const int S = (CS > 0) ? CS : ((G + 15) & ~15);
  gS = S;
  if (S > 320 || G > 640 || n + 32 > MAXN || n > 60000) {   /* [K9X-O16] 末项=ordx u16 的显式不变量(由前两项已蕴含) */ for (int i = 0; i < n; i++) out[i] = 0; return; }
  for (int i = 0; i < 17; i++)
    for (int j = 0; j < 16; j++) maskTab[i][j] = (u16)(j < i ? 0xFFFFu : 0u);
  for (int i = 0; i < BB; i++) laneB[i] = (signed char)(i ^ 0x80);

  /* ---- y and z ranks in one fused pass ---- */
  memset(cnt, 0, (size_t)(n + 1) * 2);
  for (int i = 0; i < n; i++) cnt[y[i]]++;
  pfx16(cnt, stv, curs, n);
  for (int i = 0; i < n; i++) { u32 v = y[i]; meta[i] = ((u64)stv[v] << 48) | (u64)curs[v]++; }

  memset(cnt, 0, (size_t)(n + 1) * 2);
  for (int i = 0; i < n; i++) cnt[z[i]]++;
  pfx16(cnt, stv, curs, n);
  for (int i = 0; i < n; i++) { u32 v = z[i]; meta[i] |= ((u64)stv[v] << 32) | ((u64)curs[v]++ << 16); }

  /* ---- x order ---- */
  memset(cnt, 0, (size_t)(n + 1) * 2);
  for (int i = 0; i < n; i++) cnt[x[i]]++;
  pfx16(cnt, stv, curs, n);
  for (int i = 0; i < n; i++) { u32 v = x[i]; ordx[curs[v]++] = i; }
  for (int e = 0; e < n; e++) {
    const int i = ordx[e];
    const u64 m = meta[i];
    unsigned xv = x[i];
    if (xv > 0x3FFF) xv = 0x3FFF;
    QA[e] = ((m >> 48) << 42) | ((((m >> 32) & 0xFFFF)) << 28) | ((u64)i << 14) | (u64)xv;
    QB[e] = (u32)((m & 0xFFFF) | (((m >> 16) & 0xFFFF) << 14));
  }

  /* ---- structures (H/YZ/ZY are updated at INSERT time; CP is a snapshot) ---- */
  memset(H, 0, (size_t)G * S * 2);
  memset(CP, 0, (size_t)G * S * 2);
  memset(YZ, SENTB, (size_t)n * 2 + 32);
  memset(ZY, 0x7F, (size_t)n + 32);
  padrec();
  int nrec = 0;

  int p = 0;
  while (p < n) {
    int q = n;   /* [K9X-SENT] 走完即终点,省掉每轮 `q = e + 1` */
    const u32 xv = (u32)(QA[p] & 0x3FFF);
      for (int e = p; e < n; e++) {
        const u64 m = QA[e];
        if ((u32)(m & 0x3FFF) != xv) { q = e; break; }   /* [K9X-SENT] e==p 时该式恒假,原 `e>p` 守卫冗余 */
        const u32 ky = (u32)(m >> 42), kz = (u32)((m >> 28) & 0x3FFF);
        const int FY = (int)BLKIDX(ky), FZ = (int)BLKIDX(kz);
        u32 c = (FY > 0 && FZ > 0) ? CP[(size_t)(FY - 1) * S + (FZ - 1)] : 0;
        __m256i edge1 = scanv(YZ + ((size_t)BLK0(FY)), (int)BLOFF(ky), (int)kz);
        __m256i edge2 = scanb(ZY + (size_t)BLK0(FZ), (int)BLOFF(kz), (int)FY);
        __m256i recent = scanbrec((int)FY, (int)FZ, nrec);
        __m256i all = _mm256_add_epi8(_mm256_add_epi8(edge1, edge2), recent);
        __m256i sums = _mm256_sad_epu8(all, _mm256_setzero_si256());
        __m128i halves = _mm_add_epi64(_mm256_castsi256_si128(sums), _mm256_extracti128_si256(sums, 1));
        c += (u32)_mm_cvtsi128_si64(halves) + (u32)_mm_extract_epi64(halves, 1);
        out[(m >> 14) & 0x3FFF] = c;
      }
    for (int e = p; e < q; e++) {
      const u32 b = QB[e];
      const u32 ry = b & 0x3FFF, rz = b >> 14;
      H[(size_t)BLKIDX(ry) * S + BLKIDX(rz)]++;
      YZ[ry] = (u16)rz;
      ZY[rz] = (u8)BLKIDX(ry);
      recY[nrec] = (u8)BLKIDX(ry);
      recZ[nrec] = (u8)BLKIDX(rz);
      if (++nrec == XB) { rebuild_cp<TSC>(G); nrec = 0; padrec(); }
    }
    p = q;
  }
}
#pragma GCC pop_options


void count_3d(int n, const unsigned *x, const unsigned *y, const unsigned *z, unsigned *out) {
  if (n == 10000) engine_t<79, 80>(n, x, y, z, out);
  else            engine_t<-1, -1>(n, x, y, z, out);
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #1336.85 us416 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-11-04 10:42:48 | Loaded in 1 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠