/* Adopted 2026-10-31 by campaign seat agg4 from public duck.ac submission 140476
* (https://duck.ac/submission/140476, saffah_codex_6a_agg3, Accepted 97.142424 ms,
* C++17, problem 1016b); the complete source and every inherited citation/license
* notice below are retained verbatim. The cited public submission is a duck.ac site
* submission and declares no separate license; it is credited by account and
* submission URL. Used: the whole submission verbatim as this file's body; this
* adoption changes no code character, so the only difference from our previous best
* (submission 139887) is the rival's five recorded mechanisms: MAXQ 4096->240 row
* capacity, ten-plane eight-point s_pm transposition, aligned eight-coordinate bound
* rows plus a separate coordinate8 bound, the D8/D9 single scalar high comparison,
* and the D0 lower-bound prefetch removal. */
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/140472 supplies the accepted aligned-eight-plus-one-bound engine and all inherited notices below. No separate license was declared; no external code is introduced.
* Idea: the static D0 fringe sets qT=qr and qTh=qrh, so it never reads either bound pool. Omit only D0's lower-bound prefetch, retaining its point/rank/output hints and every bound hint in D1..D9, including the separate coordinate8 hint in D9.
* Purpose: remove a prefetch stream with no consumer during that dimension, reducing cache traffic while leaving all arithmetic, ordering and every actual load/store unchanged.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/140113 supplies the accepted static-fringe ten-dimensional engine with all inherited notices below. Our https://duck.ac/submission/140413 uses aligned eight-coordinate bound rows in the nine-dimensional large sibling; this candidate retains the additional live coordinate8 bound separately because ten dimensions still need it. No separate license was declared.
* Idea: all fringe exclusions use e<D. Thus bound9 is never read, and bound8 is read only by D9; all other exact bound accesses use the first eight coordinates. Store those eight in aligned32-byte rows and retain bound8 in its own scalar array, loading/prefetching it only in D9. Preserve anchor-neutral INT_MAX values, all maxr entries and original point/signature rows. This avoids the unaligned48-byte rows of the earlier12-slot layout.
* Purpose: nearly halve the commonly accessed bound pool while keeping every low-vector load aligned and every actual bound exact. The public entry of this file is count_10d, so the producer retains all ten metadata dimensions and only removes provably unconsumed bound storage.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/140094 supplies this validated ten-dimensional compact-capacity engine, retaining all inherited notices. https://duck.ac/submission/140100 supplies tight cache-line metadata strides in the eight-dimensional sibling. No separate license was declared; original credits remain below.
* Idea: the proven maximum runtime Q is234 for every n<=100000, requiring235 slots. Round only to the next16-counter cache line, MAXQ240, instead of256. Each row begins15 cache lines after the previous row rather than16, avoiding repeated row starts in only four L1 sets. All required live/terminal slots and original runtime Q/B/g_MS remain unchanged; maxima contents, bitmap pools, query/fringe loops and comparisons are identical.
* Purpose: test removal of the last16 unused counters per physical row and a distributed row stride after the accepted4096-to256 capacity reduction. No bucket-count parameter or mathematical partition is changed.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/139950 supplies the current ten-coordinate transposed-row engine and all inherited credits below. https://duck.ac/submission/140033 supplies the compact physical metadata-capacity mechanism in the seven-coordinate engine. No separate license was declared; original notices are retained.
* Idea: the problem specifies n=100000. For every1<=n<=100000, ceil(sqrt(n))<=317, ceil(317*57/100)=181 and ceil(181*129/100)=234, before any memory-cap reduction. Thus every bucket and terminal slot is below256. Change only physical MAXQ capacity4096->256, removing unused page-strided space between fold positions, offsets and lengths; preserve runtime Q/B, g_MS=Q+1, actual maxima, all bitmap contents and fringe arithmetic.
* Purpose: test metadata locality and reduced address footprint with identical bucket geometry. Independently exhaust all100000 supported sizes to verify the capacity bound, and compare full outputs against the accepted source.
*/
// References: saffah_codex_6a_agg3 https://duck.ac/submission/139916 supplies this ten-dimensional engine, retaining all inherited credits. Our https://duck.ac/submission/139922 demonstrated eight-point original-coordinate transposition for seven dimensions; this adapts that producer to ten dimensions and its existing 64-byte row stride.
// Idea/Purpose: read eight consecutive coordinates from each input plane. Transpose the first eight planes into eight 32-byte row prefixes; interleave the final two planes into eight 8-byte row suffixes. This replaces eighty scalar coordinate reads and scattered row stores with ten wide reads and the same forty live bytes per point, preserving all row padding, query thresholds, signatures and consumers. Keep the original scalar tail and all other dimension paths.
// References: saffah_v41f1017_agg4 https://duck.ac/submission/139887 provides the fixed-dimension global-fringe engine and saturated query-signature construction; its complete inherited credits and licenses remain below. saffah_codex_6a_agg3 https://duck.ac/submission/129275 used the known fringe coordinate to omit the sole high coordinate in the nine-dimensional sibling.
// Idea/Purpose: in ten dimensions, for fringe dimensions8 or9, candidate rank j<gt[D][query] already proves candidate[D]<query[D]. The folded threshold at D is exactly the query coordinate because only e<D thresholds are folded. The high half therefore has just one remaining real comparison. Replace the corresponding exact ambiguity check by that scalar comparison, and save only its4-byte threshold in the existing per-candidate high-threshold slot. Preserve queue capacity/stride, all lower-eight comparisons, full checks at dimensions0..7, strict ties, and pure fallback paths. No extra query scan or lookup table is introduced.
/* ===== agg4 单发叠加(saffah_v41f1017_agg4,2026-10-22)=====
* 引用区:
* [1] saffah_codex_6a_agg3,提交 https://duck.ac/submission/139776 —— 本文件正文的逐字节母本
* (1016b,现 T=101,648.099µs),其自带全链引用/署名/许可块原样保留在下方(未删改)。
* duck.ac 公开提交,无独立许可证声明;按账号+URL+沿用内容具名引用。
* [2] 本账号 saffah_v41f1017_agg4 提交 https://duck.ac/submission/139805 —— 现 best 101,666.522µs,
* 即 [1] 正文(本文件在其上做两处单变量叠加)。
* [3] duck.ac/problem/1016b。
* 站外资料:无。
* 思路区(两处值精确真改动,均只改 dimension_major_fringe 的 pair 环):
* [SIGSB] 签名阈值构造的饱和减一外提:原式对每个 e 做
* qsb[e] = subs_epu8(shuffle_epi8(src, mask4[e&3]), 1) —— 每对 9 次 vpsubusb;
* 因 mask4 只取 32 位 lane 的第 0 字节,而把 subs_epu8(·,1) 移到 shuffle 之前、作用于
* 整个 sig 向量(第 1..3 字节为 0 或 0/1,饱和减后仍为 0,永不被 mask 选中),
* lane 第 0 字节逐位相同 ⇒ 9 次 vpsubusb 降为 2 次,其余逐字未动。
* [CFD] 维度 d 编译期化:原 pair 环在 d 循环体内,`if (e==(int)d)` 与 d==0 / d<=8 分支
* 迫使 GCC 对 d 做循环去开关(unswitch),逐对产生 9 次 d 比较/跳转与阈值的重量化、
* 栈溢出;现将 d 循环体抽为 template<int KK,int D> fr_dim 并按 D=0..9 十路分派
* (每维只分派一次),e==D、D==0、D<=8 全部编译期折叠。语义逐字相同(D 即原 d)。
* 值闸:判题同源 g++15.2 -O2 -std=c++17;官方 cfg(n=1e5 seed12345 mode10)checksum=9903724
* 逐位同;另 19 组输入(mode=1 重复值/mode=2/mode=3、n=1e5/99999/65536/50000/25000/4096/
* 12345/1000/777/100/33/3/1、gq=200/251)全输出 FNV 与母本逐位同。
* 判题机不可用(本席不提交);本地 in-engine 交错 A/B(同机同源,16 轮取 min,fringe 相区间
* rdtscp 实测):base 167.99M 拍 → [SIGSB] 162.80M(−3.1%)→ [SIGSB+CFD] 146.15M(−13.0%)。
* 母本 fringe 占总时 45.1%(协调席判题 phase 探针)⇒ 预计整机 −5% 量级。
* 目的:把 1016b 从 101,666.522µs 压到严阈 100,632.618µs 以下(需 −1.028%)。
* ================================================================ */
/* Adopted 2026-10-22 (agg4 main) from public duck.ac submission 139776 by saffah_codex_6a_agg3 (https://duck.ac/submission/139776): packed-first-anchor10D engine plus global-fringe removal of per-anchor counting sorts; inherited notices retained; public submission, no separate license stated. */
// References: saffah_codex_6a_agg3 https://duck.ac/submission/139647 supplies the latest packed-first-anchor10D engine and inherited notices below. https://duck.ac/submission/139740 supplies the successful global-fringe removal of per-anchor counting sorts on1014a; that schedule originates with saffah_v41f1017_agg4 https://duck.ac/submission/139705 on1016a.
// Idea/Purpose: complete all full-prefix bitmap answers first, then scan each existing coordinate order once for fringe queries, grouped by the same tie-aware bucket intervals. Delete this engine's repeated query histogram/scatter from every anchor-by-dimension pair. Skip each query's own anchor; its Av lane is alreadyINT_MAX, so a dimension-only earlier-coordinate mask preserves every threshold.
// Preserve unsigned-biased signatures, the original16-bit result representation, exact fallback and deferred exact arrays. The final32-bit output sweep remains after both components. Deferred entries now flush per dimension instead of per anchor-dimension, with the existing capacity checks and immediate fallback unchanged. No allocation/layout or input data changes.
// References: saffah_v41f1017_agg4 https://duck.ac/submission/135058 supplies the1016b engine and all inherited notices below; https://duck.ac/submission/136989 and https://duck.ac/submission/137126 supply first-anchor bucket packing in1016.
// Idea/Purpose: while the initial stable fold scatter already knows each point and fold, pack its first non-fold bucket above the20-bit point ID. The initial anchor count/scatter then consumes that sequential packed record instead of gathering s_bdT and writing/reading s_bkt.
// After the first anchor scatter, explicitly restore pure point IDs so every existing fringe path stays unchanged. The pre-query wide-rank fallback masks the ID; non-ASCR builds keep plain IDs. MAXN<2^20 and bucket<=255 guarantee disjoint exact fields.
// No new arrays or ordering changes; keep cached narrow/wide ranks, output counters, masks, all later sorts and their pointer swaps intact.
// ===== 本发(saffah_v41f1017_agg4)单变量 [PDPART8] =====
// 引用区:
// [1] 本账号 saffah_v41f1017_agg4,提交 #134949 <https://duck.ac/submission/134949>(104.263 ms,rank1)= 本文件正文;
// 其上游全链引用/署名/许可原样保留于下方全部原头块。
// [2] duck.ac 题目页 <https://duck.ac/problem/1016b>(站点 FAQ 明示提交正文可见)。
// 思路区:单变量 —— per-dim 计数排序散播的值域分段(L2 工作集定位)。
// 【动机·判题机实测】同一散播环在 n=100k/50k/25k/12.5k 下为 24.25 / 20.84 / 16.60 / 15.26 拍/点
// (直方控制相 2.97/2.27/2.12/2.20 基本持平)⇒ 该环受两个 4N 字节随机数组(ct 计数、od 秩位)超出
// L2 256KB 所限;50KB 级数组时每点便宜 ~9 拍。
// 【本发】把每维散播按值域 8 分段:在原有 per-dim 值直方波(hc[v]++)中顺带累计段计数并把等价
// (v<<32|i) 稳定写入按段预留的槽区(段基 = s*N,容量 N,静态 u64 表);散播体随后逐段读取本段列表
// 并按原式处理 —— 段内 ct 活跃窗 ~64KB + od 活跃窗 ~50KB < L2。同值点的处理次序仍为 i 升序 ⇒
// od/rank16/gt/bdT 与底盘逐位相同(值精确);直方结果 hc、前缀、桶界、池建、查询全部逐字未动。
// 【负对照·同批透明】仅分段不融合(独立分段趟):同轮 −0.234%/−0.251%/−0.295%(均值 −0.260%);
// 16 段 +0.175% 负;桶级批化预取 +1.62% 负(均不采用)。
// 判题 in-engine 交错 A/B(官方 cfg n=1e5 seed12345 mode10,3 轮交错,checksum 全 9903724):
// base(#134949 正文)374,899,392 / 375,011,698 / 375,126,520
// vs 本发 373,519,310 / 373,586,784 / 373,360,376 ⇒ −0.368% / −0.380% / −0.471%(3/3 同向,均值 −0.406%)。
// 值闸:本地 gcc9 与判题 experience 全臂 checksum=9903724 逐位同;另以 mode=1(重复值)与 seed=777 输入
// 对底盘逐位同(9903724/173045/9788537 三类均 MATCH);纯遍历/分段序改动,逐点算术与写出式逐字不变。
// 目的:官方单发真实单变量改进;best 104.263ms,严阈 103,956.94µs,缺口 306.06µs(0.29%≤0.3%)⇒ 单发不重掷。
// ==============================================
// ===== 本发(saffah_v41f1017_agg4)单变量 [CG2-q_al32] =====
// 引用区:[1] 本账号 #134747 <https://duck.ac/submission/134747>(104.291 ms,rank1)= 本文件正文;
// 其上游全链引用/署名/许可原样保留于下方全部原头块。
// 思路区:单变量编译器/代码生成类 —— query_group 的 optimize 属性加 align-loops=32(热核/边缘函数循环对齐;其余逐字未动);纯编译选项/属性,零语义/数据改动。
// 值闸:判题同源 n=1e5 官方 cfg checksum=9903724 逐位同;对象级 .text 与底盘不同(真码变,非等价件)。
// 判题 in-engine 交错 A/B:base 375,176,828 vs q_al32 375,277,424 (+0.027%, 2 轮交错, chk 全 9903724)
// ==============================================
// ===== 引用区 REFERENCES(saffah_v41f1017_agg4,2026-10-18)=====
// [1] 本账号 saffah_v41f1017_agg4,提交 #134724 <https://duck.ac/submission/134724>
// (104.393 ms,2026-10-18 11:10:40,rank1)—— 本文件正文母本(4 点手写 asm 散播组 +
// shrq $6/scale-8);本发仅在该组主循环加一条 od 流 PREFETCHNTA,其余代码逐字未动;
// #134724 自带的完整 References/引用链/许可块原样保留于本头部之后,未删改。
// [2] saffah_codex_6a_agg3,提交 #134188 <https://duck.ac/submission/134188>(105.006 ms,现役 T)
// —— 上游母本(经 [1] 引用链保留)。
// [3] duck.ac/problem/1016b。LICENSE:duck.ac 公开提交,无独立许可证声明;按账号+URL+沿用内容具名引用。
// 站外资料:无;本发未复制任何站外代码、论文或资料。
// ===== 思路区(本发:真实单变量 = od 流 PREFETCHNTA 128 点(512B)前瞻,防 L2 污染)=====
// 【动机/普查】散播内层每点 rank16 随机 2B 载(活跃前缀 200KB = RAM 行 1e5×2B;L2 256KB/4-way ⇒ 3.1 way/set)
// 与 od 流(每趟前缀 400KB 顺序)共用 L2;od 读一次即弃却按普通策略占 L2,可能挤出 rank16 行。
// 独立探针(判题机):16KB 小表 arm 3.662 vs base 3.905 c/pt ⇒ 表驻留全额上限仅 ~0.24 c/pt,且 200KB
// 表 + od 流共存是常态;本发用 NTA(evict-first)把 od 行标为一次性,保护 rank16 行与其余热数据。
// 【唯一改动】4 点 asm 组主循环守卫后加一条 `prefetchnta od[p+128]`(512B 前瞻;每 4 点组发 1 条,
// 每 64B 行被同组链冗余发 4 条);点语义/载批序/索引/存储逐位不变;prefetch 越界不产生异常。
// 【判题机 experience 同源 A/B(官方配置 MF_PFB3=8,n=1e5 seed12345 mode10,checksum 9903724)】
// 距离扫描(同一代码几何,仅位移立即数不同):16 点 +0.143%(T0 对照 +0.149% 同负);
// 64 −0.078%;96 −0.112%;**128 −0.149% / −0.174%(两会话四轮同向)**;256 −0.141%;512 +0.090%。
// 峰值 128–256;本发取 128(512B)。臂内复跑差 ≤0.05%。
// 【目的】官方兑现 od-NTA 的 L2 抗污染收益(bench −0.15~−0.17%);严阈 103,956.94µs(gap 436.06µs),
// 本发后仍预计未 met ⇒ 单发真改进、不重掷。
// ================================================================
// ===== 引用区 REFERENCES(saffah_v41f1017_agg4, 2026-10-18)=====
// [1] 本账号 saffah_v41f1017_agg4,提交 #134628 <https://duck.ac/submission/134628>
// (104.978 ms,2026-10-18 08:30:57,rank1)—— 本文件正文母本(本发仅改两处 locality 提示);
// 其自带的完整 References/引用链/许可块原样保留于本头部之后,未删改。
// [2] saffah_codex_6a_agg3,提交 #134188 <https://duck.ac/submission/134188>(105.006 ms,现役 T)
// —— #134628 的母本(经 [1] 引用链保留)。
// [3] duck.ac/problem/1016b。LICENSE:duck.ac 公开提交,无独立许可证声明;按账号+URL+沿用内容具名引用。
// ===== 思路区(本发:真实单变量 = 预取 locality 提示;空窗单发,取更好 best) =====
// 【底盘】#134628(104.978 ms,rank1)。
// 【本发唯一改动】下一查询元数据预取(MF_PFA 前瞻 1 查询,ASCR 活路径)的两条 _mm_prefetch
// s_bd[j*MAXK] 与 s_g[j] 的 locality 提示 _MM_HINT_T0 → _MM_HINT_NTA(纯提示,读写集/比较/输出逐位不变)。
// 【判题机 experience 同源 bench(n=1e5 seed12345 mode10,官方同尺度,checksum 9903724)】
// 紧邻交替 A/B 三批:base 377.90/377.90/377.96M vs NTA 377.31/377.27/377.19M cyc
// = −0.167%/−0.167%/−0.204%(每批 2-4 发,臂内差 ≤0.03%);19 臂 locality 扫中唯一同向项。
// 【locality × 距离正交】距离 {0=去掉预取: +5.5%, 1: −0.18%, 2: +0.13%};locality {NTA: −0.18%,
// T2: +0.35%, T1: +0.31%, T0: 基线} ⇒ 距离 1 × NTA 为尖峰。拆分:s_bd 单独 NTA −0.07%、
// s_g 单独 −0.13%、双 NTA −0.20%(方向可加)。
// 【值闸门】本地 gcc 与判题机 experience 全臂 checksum 9903724 逐位相同。
// 【目的】把官方 best 从 104.978 ms 压到 ~104.79 ms(真实改进);严阈 103,956.94µs 仍差 ~0.8%,
// 缺口>0.3% ⇒ 按纪律空窗单发、不重掷。
// ================================================================
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/134176,
* terminal-prefix base below; https://duck.ac/submission/134144 and
* saffah_v41f1017_agg4 https://duck.ac/submission/133312, unsigned biased
* three-state signatures used on1016. Earlier1016b signed-max experiment
* https://duck.ac/submission/128598 uses a different signed reduction.
* Idea/Purpose: store max(raw_signature,1), query max(raw_signature-1,0).
* OR unsigned saturated differences once: zero is strictly safe, one requires
* exact replay, greater rejects. This removes the conditional second nine-plane
* equality scan; zero signatures become conservative exact candidates.
* Preserve every plane/layout/traversal, full-value thresholds and exact replay.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/134154,
* latest1016b engine below; https://duck.ac/submission/129117 (1015a) and
* https://duck.ac/submission/129332 (1016), clamped-bucket unused-row proof.
* Idea/Purpose: every1016b query bucket is clamped below Q. The ordinary
* builder's final b=Q row has no reader; omit its suffix insertions and copy.
* Preserve all allocations, row offsets, rows0..Q-1, narrow-rank correction,
* fences and fringe calculations. Independently test this deletion here.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/134137,
* anchor-boundary base below, and https://duck.ac/submission/134144,
* packed selected-rank record on1016. Idea/Purpose: retain the already known
* minimum rank in the high28 bits of each existing fold word; queries read
* this one table instead of ten rank tables. Mask dimension for stable scatter.
* No extra arrays, stores or numerical changes; MAXN<2^28 ensures exact packing.
*/
/* References: saffah_codex_6a_agg3, https://duck.ac/submission/134119,
* direct stable fold scatter and inherited implementation below; and
* https://duck.ac/submission/134111, consumed-scatter boundary reuse.
* Idea/Purpose: the anchor-bucket stable scatter already leaves each exact
* bucket end in cntv[b+1]. Reuse those ends until the later fringe sorts,
* removing the bitmap stage's repeated byte scan over the same query IDs.
* Optional lexicographic reordering retains its original boundary scan.
* All bitmap/fringe mathematics, order and bucket byte records are unchanged.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/134111: complete retained
* fold endpoints and maxima engine; all earlier notices remain below.
* Idea/Purpose: the stable fold scatter's input permutation is exactly iota.
* Consume each ascending point ID directly instead of first writing s_qord[i]=i
* and loading it back. Preserve the histogram, cursor prefix, stable scatter,
* copied result permutation, fold endpoints and every later traversal. Unlike
* direct-stable-fold-order, this neither fuses producers nor changes grouping.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/134103: current full engine
* and retained fold extent; all inherited references and licenses follow.
* Idea/Purpose: immediately after stable fold scatter, cursor[d] is exactly
* the end of fold d-1. Copy these ten endpoints into gstart instead of walking
* every reordered query and randomly reading its fold label again. Empty folds
* preserve equal endpoints; zero and N sentinels remain exact. Keep the original
* producer, stable scatter, full qord copy, data layouts and downstream order.
* This does not change fold traversal as in the old direct-stable-fold variant.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/134065: complete current
* retained-rank and three-chain bitmap engine; original notices follow.
* https://duck.ac/submission/129419 (1015): reuse already-produced per-bucket
* rank maxima rather than repeat a random query-rank scan, adapted here to the
* whole-fold WTRIM extent, not the ASCR per-anchor copy extent.
* Idea/Purpose: s_maxr[fold][one non-fold dimension][bucket] partitions every
* point of this fold. Its maximum is exactly max s_gt[fold][query]. Reduce this
* small contiguous row instead of loading qord then random gt for every point.
* Keep the old scan when length metadata is disabled. Narrow/wide rank boundary,
* sentinel corrections and all pool lengths are unchanged; mx still starts at1.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/134049: full retained-rank,
* vector-signature engine; all original references and notices follow.
* Existing AND256M / nine-stream balanced-tree methods are retained and adapted.
* Idea/Purpose: group the nine bitmap operands into three independent triples,
* each with one wide load and two existing memory-operand ANDs. Combine the
* three triples with two register ANDs. Boolean operations, nine read intervals,
* four-level maximum dependency depth and both-vector popcount cadence remain
* exact; six standalone load instructions are folded into their sole consumers.
* This differs from a serial nine-input chain and preserves independent triples.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/134030: retained halfword rank
* engine and all inherited notices below.
* saffah_codex_6a_agg3 https://duck.ac/submission/129369: eight-point vector
* signature production and transpose, adapted without its zero-to-one bias.
* Idea/Purpose: produce the existing16-byte signature cache rows eight at a time.
* Coordinates0..N-1 times floor((255<<23)/(N-1)) fit below2^31, so low32 vector
* multiplication exactly matches the full64 scalar result. Preserve raw zero,
* all ten bytes, ordered-plane transpose, every query and the scalar tail.
*/
/* References:
* saffah_v41f1017_agg4, https://duck.ac/submission/133065: complete current
* 1016b bitmap/signature engine; inherited references and licenses follow.
* saffah_codex_6a_agg3, https://duck.ac/submission/134004: retain stable ranks
* at their sorting producer instead of rebuilding inverse permutations later.
* Idea: retain capped 16-bit stable ranks for every dimension during scatter.
* Bitmap construction consumes this table directly, removing each group's
* random inverse scatter and its prefetch pass. Ranks >=65535 retain the old
* sentinel and wide-query correction. For a narrow group, ranks >=max query R
* may set unused bits, but every consumer masks at its own R; allocated s_acc
* still covers all capped positions. Existing full-rank fallback is unchanged.
* Purpose: test eliminated random inversion work on the 100,000-point engine.
*/
// ===== 引用区 =====
// [1] 原作者账号: saffah_cc_v41_agg1
// 原提交 URL: https://duck.ac/submission/129065 (sid=129065, pid=1016b, 107.933ms, 现役 T 件)
// 所用内容: 直接完整复制其本题提交正文(为满足长度限制由编译器预处理去注释,代码逐字节等价,
// 同输入 checksum 相同),并在其上做下述单变量改动。
// [2] 上述提交正文的逐字节来源(其文件头自述): saffah_codex_6a_agg3,
// https://duck.ac/submission/128854。
// [3] 其正文内继承的全链引用(原注释所列提交号,逐一列明):
// #106852, #107375, #107650, #108176, #109755, #109919, #109953, #111528, #111559, #120185, #120248, #120278, #120294, #120633, #120802, #120873, #120939, #121103, #122788, #123209, #123223, #123963, #125836, #126019, #126039, #126047, #126279, #127150, #127228, #127289, #127339, #127426, #127446, #127574, #128242, #128356, #128394, #128708, #128725, #128746, #128824, #128854
// 许可证遵守: duck.ac 公开提交均未附独立许可证声明;按项目 INSTRUCTIONS 要求在同一评测站内
// 逐项注明原作者账号与原提交 URL 后使用;本发不新增第三方代码。
// ===== 思路区 =====
// 本次提交 = 107.404ms 件 + 三处单变量(评测机 gcc9.3 rig 逐一实测):
// ① 只保留 k=10 例化的等价引擎(剪掉 k=4..9 的 query_group 实例;本题只调用 count_10d)⇒ 布局/码址变化;
// ② and_popcount_range(AND+popcount 热点)用 __attribute__((optimize("O2","no-tree-vectorize"))) 编译;
// ③ query_group 用 __attribute__((optimize("O3","no-jump-tables","no-split-loops")));
// 并沿用 MF_FILTAUTO=0 + MF_QCOEF=57(自动分块 Q=234/B=428)。
// rig: 基线 110.588 → trim+APC+qg+Q234 109.966(−0.56%)。目的: 逼近 0.99*T+1us=106.8547ms。
// 本发在前件基础上再叠一个单变量(判题机 experience 通道 A/B,同输入 checksum=9903724):
// ④ 池构建的位散播内层(每 group×dim 遍历 N 个点设 bit)去掉 s_nid16 的 prefetch,
// 并删掉冗余的 ((q>>6)|(q<<26))&1023 伪装(等于 q>>6)。判题机 A/B:
// 基线 386.46–386.64M cyc → 本发 385.67–385.89M cyc(−0.20%)。预取反噬的原因:
// 该环已是 load-port 受限(每点 od 载入 + nid16 随机载入 + cur RMW),预取额外占
// 一个 load 槽且其 od[ptr+26] 载入使 od 被读两遍;去掉后 od 只读一遍。
// 目的: 把严格阈值 106.8547ms 的缺口从 0.488% 压到 ~0.29%。
// ⑤ 同池构建环同源的「按点建 avpool/s_maxr」小环去分支化(本发主体增益):
// 原式对每点 10 个 d 逐一 `if (d == ds) { av[d]=0x7FFFFFFF; continue; }`;ds 是逐点
// 随机值(argmin 维),该 10 连 cmp+jcc 的数据相关模式造成大量误预测。改为:
// 10 个 d 全部无条件写 av[d]=BVAL 与 s_maxr 的 branchless max(`*mp=max(*mp,best)`),
// 最后一条 av[ds]=0x7FFFFFFF 覆盖。写入 (ds,d==ds) 对角元是安全的——plen/poolwords
// 两处读取都显式取 d != ds,对角元从不被读(已逐一核对 s_maxr 的全部读取点)。
// 判题机 interleaved A/B(3 轮交替): 385.78/385.81/385.98M → 382.27/382.25/382.36M
// cyc = **−0.93%**;n=2e4/1e5/1e5+3、seed 1/2/3/5/7/999、含 v%3 重值模式 checksum 全等。
// 目的: 382.3M cyc ≈ 106.2ms,低于严格阈值 106.8547ms。
// ============================================================
#define MF_FILTAUTO 0
#define MF_NOSDMP 1
#ifndef PF_DIST
#define PF_DIST 4
#endif
#pragma GCC optimize("O3,unroll-loops,no-strict-aliasing,align-functions=64")
#pragma GCC target("avx2,bmi,bmi2,popcnt,lzcnt,tune=skylake")
#undef __code_model_small__
#undef __MMX_WITH_SSE__
#define __tune_skylake__ 1
#define __code_model_small__ 1
#define __SSE3__ 1
#define __SSSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __AVX__ 1
#define __AVX2__ 1
#define __BMI__ 1
#define __BMI2__ 1
#define __LZCNT__ 1
#define __CRC32__ 1
#define __POPCNT__ 1
#define __XSAVE__ 1
#define __MMX_WITH_SSE__ 1
#pragma GCC optimize("web")
#pragma GCC optimize("rename-registers")
#pragma GCC optimize("live-range-shrinkage")
#pragma GCC optimize("align-functions=32")
#include <immintrin.h>
#include <type_traits>
#include <sys/mman.h>
#include <stdint.h>
#ifndef MADV_HUGEPAGE
#define MADV_HUGEPAGE 14
#endif
static int g_hug = 1;
static long g_madv_ok = 0, g_madv_err = 0, g_madv_bytes = 0;
static void t16h_hugify(void *p, size_t len) {
uintptr_t a = (uintptr_t)p;
uintptr_t s = (a + 0x1FFFFFULL) & ~(uintptr_t)0x1FFFFFULL;
uintptr_t e = (a + len) & ~(uintptr_t)0x1FFFFFULL;
if (e > s) {
if (madvise((void *)s, (size_t)(e - s), MADV_HUGEPAGE) == 0) { g_madv_ok++; g_madv_bytes += (long)(e - s); }
else g_madv_err++;
}
}
extern "C" void *malloc(unsigned long);
typedef unsigned u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef unsigned long long u64;
#define LDU256(p) ({ __m256i _v256; __asm__("vmovdqu %1, %0" : "=x"(_v256) : "m"(*(const __m256i *)(p))); _v256; })
#define AND256M(a,p) ({ __m256i _r256; __asm__("vpand %2, %1, %0" : "=x"(_r256) : "x"(a), "m"(*(const __m256i *)(p))); _r256; })
#ifndef MAXN
#define MAXN 1000005
#endif
#define MAXK 10
#define STRIDE 16
#ifndef MF_APF
#define MF_APF 0
#endif
#ifndef MF_QCOEF
#define MF_QCOEF 57
#endif
#ifndef MF_KSPAD
#define MF_KSPAD 1
#endif
#ifndef MF_FILTAUTO
#define MF_FILTAUTO 1
#endif
#ifndef MF_NT
#define MF_NT 1
#endif
#ifndef MF_FR_NOSORT
#define MF_FR_NOSORT 0
#endif
#ifndef MF_FR_NOCAND
#define MF_FR_NOCAND 0
#endif
#ifndef MF_BUILD_NOPOOL
#define MF_BUILD_NOPOOL 0
#endif
#ifndef MF_FR_NOREAD
#define MF_FR_NOREAD 0
#endif
#ifndef MF_NOSDMP
#define MF_NOSDMP 0
#endif
#ifndef MF_FB2
#define MF_FB2 0
#endif
#ifndef MF_FB3
#define MF_FB3 1
#endif
#ifndef MF_PLEN
#define MF_PLEN 1
#endif
#ifndef MF_BUDGETMB
#define MF_BUDGETMB 1900
#endif
#ifndef MF_NOFILTB
#define MF_NOFILTB 0
#endif
#ifndef MF_PFB
#define MF_PFB 16
#define MF_PFB1 96
#define MF_PFB2 96
#define MF_PFB3 8
#endif
#ifndef MF_ASCR
#define MF_ASCR 1
#endif
#ifndef MF_WTRIM
#define MF_WTRIM 1
#endif
#define AS_WORDS 20480
#ifndef MF_PFA
#define MF_PFA 1
#endif
#ifndef MF_FR_NOMETA
#define MF_FR_NOMETA 0
#endif
#ifndef MAXQ
#define MAXQ 240
#endif
static u32 s_ord[MAXK][MAXN];
static u32 s_gt[MAXK][MAXN];
static u32 s_pm[(size_t)MAXN * STRIDE] __attribute__((aligned(64)));
static u8 s_bd[(size_t)MAXN * MAXK];
static u8 s_bdT[(size_t)MAXK * MAXN];
static const unsigned char mask4[4][32] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4},
{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
{12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12}};
/* [L1MERGE] one 8 B per-point record {g, cnt}: the fringe fold nibble (s_g) and the 16-bit
output accumulator (s_outlo) now share a cache line, so a query's prologue touches one
random line instead of two (the PFB3-served line carries both). Values/widths unchanged. */
struct GCrec { u32 g; u32 cnt; };
static struct GCrec s_gc[MAXN] __attribute__((aligned(64)));
static inline void add_out16(u32 i,u32 add) {s_gc[i].cnt=(u32)(u16)((u32)(u16)s_gc[i].cnt+add);}
static u32 s_qord[MAXN], s_tmp[MAXN], s_cntv[MAXN];
static u64 s_fpl[(size_t)8*MAXN];
static u8 s_hist8[MAXN+8];
static u32 s_pk32[MAXN + 8];
static u64 s_pk[MAXN + 8];
static u8 s_bkt[MAXN];
static u8 s_bka[MAXN];
static u8 s_bks[MAXN];
#define MF_SPL ((size_t)100064)
#define AMBD_CAP 4096
static u32 s_abi[AMBD_CAP];
static const u32 *s_abp[AMBD_CAP];
static __m256i s_abqT[AMBD_CAP], s_abqTh[AMBD_CAP];
static u32 s_nid[MAXN];
static u16 s_nid16[MAXN];
static u16 retained_rank16[MAXK][MAXN];
static int g_nid16 = 0;
static int g_nidwide = 0;
static u32 g_nidmx = 0;
static u32 s_pos[MAXK][MAXN];
static u32 s_posp[(size_t)MAXK * MAXN];
static u64 s_facc[(size_t)(MAXK - 1) * (((MAXN) + 63) / 64 + 16)];
static u32 s_bnde[(size_t)MAXK * (MAXQ + 2)];
static u64 *s_fbm = 0;
static u64 s_fbuf[8192] __attribute__((aligned(64)));
static __m256i khi8v, khi8hv;
static u32 g_Qc = 32;
static u32 g_fbm_W = 0;
static int g_use_filt = 0;
static int g_lexsort = 0;
static int g_nofilt = 0;
static u32 s_fpos[(MAXK + 1) * MAXQ];
static u32 s_bval[(MAXK + 1) * (MAXQ + 1)];
static u64 *s_bs = 0;
static u64 s_acc[MAXN / 64 + 256] __attribute__((aligned(64)));
static u32 *s_sdmp[MAXK];
static u64 s_ascr[AS_WORDS] __attribute__((aligned(64)));
static u32 s_maxr[(size_t)MAXK * MAXK * (MAXQ + 1)];
static u32 *s_avpool = 0;
static u32 s_av8[MAXN] __attribute__((aligned(64)));
static size_t s_avcap = 0;
static u8 *s_sig = 0;
static int g_sig_on = 0;
static int g_sig_merged = 0;
static u32 g_sigsh = 0;
static u32 g_sigmul=1;
static inline u8 sigfull(u32 x){return (u8)(((u64)x*g_sigmul)>>23);}
static void prepare_cached_signatures(u8 *dst,const unsigned **x,u32 N){
const __m256i mul=_mm256_set1_epi32(g_sigmul),one=_mm256_set1_epi32(1);
const __m256i gather=_mm256_setr_epi8(0,4,8,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,4,8,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1);
const __m128i mask2=_mm_set_epi64x(0,65535);
u32 i=0;
for(;i+8<=N;i+=8){
__m128i c[10];
#pragma GCC unroll 10
for(int d=0;d<10;++d){
__m256i q=_mm256_mullo_epi32(_mm256_loadu_si256((const __m256i*)(x[d]+i)),mul);
q=_mm256_srli_epi32(q,23);
q=_mm256_max_epu32(q,one);
q=_mm256_shuffle_epi8(q,gather);
c[d]=_mm_unpacklo_epi32(_mm256_castsi256_si128(q),_mm256_extracti128_si256(q,1));
}
__m128i t0=_mm_unpacklo_epi8(c[0],c[1]),t1=_mm_unpacklo_epi8(c[2],c[3]);
__m128i t2=_mm_unpacklo_epi8(c[4],c[5]),t3=_mm_unpacklo_epi8(c[6],c[7]);
__m128i u0=_mm_unpacklo_epi16(t0,t1),u1=_mm_unpackhi_epi16(t0,t1);
__m128i u2=_mm_unpacklo_epi16(t2,t3),u3=_mm_unpackhi_epi16(t2,t3);
__m128i r[4]={_mm_unpacklo_epi32(u0,u2),_mm_unpackhi_epi32(u0,u2),_mm_unpacklo_epi32(u1,u3),_mm_unpackhi_epi32(u1,u3)};
__m128i tail=_mm_unpacklo_epi8(c[8],c[9]);
#pragma GCC unroll 8
for(int p=0;p<8;++p){
__m128i lo=(p&1)?_mm_srli_si128(r[p/2],8):r[p/2];
__m128i hi=_mm_and_si128(_mm_srli_si128(tail,p*2),mask2);
_mm_storeu_si128((__m128i*)(dst+(size_t)(i+p)*16),_mm_unpacklo_epi64(lo,hi));
}
}
for(;i<N;++i)for(int d=0;d<10;++d){u32 v=sigfull(x[d][i]);dst[(size_t)i*16+d]=(u8)(v?v:1u);}
}
static u32 s_pofs[(size_t)MAXK * MAXQ];
static u32 s_plen[(size_t)MAXK * MAXQ];
static int g_plen_on = 0;
static u32 g_W, g_Q, g_B;
static u32 g_KS;
static int g_nosort = 0;
static int g_nosdmp = 0;
static int g_skip_and = 0, g_skip_fringe = 0;
static u32 g_MS = MAXQ;
#define FPOS(d,b) s_fpos[(size_t)(d) * MAXQ + (b)]
#define BVAL(d,b) s_bval[(size_t)(d) * g_MS + (b)]
static void *pool_alloc(size_t bytes) {
void *raw = malloc(bytes + (2u << 20));
if (!raw) return 0;
void *al = (void *)(((size_t)raw + (2u << 20) - 1) & ~(size_t)((2u << 20) - 1));
if (g_hug) t16h_hugify(al, bytes);
return al;
}
__attribute__((target("avx2,popcnt")))
static inline u32 hsum256(__m256i v) {
u64 b[4];
_mm256_storeu_si256((__m256i *)b, v);
return (u32)(b[0] + b[1] + b[2] + b[3]);
}
#define AND_TREE(bs,w) (KK == 9 ? and_tree9((bs), (w)) : and_tree_lin<KK>((bs), (w)))
__attribute__((target("avx2,popcnt")))
static inline __m256i and_tree9(const u64 *const *bs, u32 w) {
__m256i a = LDU256(bs[0] + w);
__m256i b = LDU256(bs[3] + w);
__m256i c = LDU256(bs[6] + w);
a = AND256M(a, bs[1] + w);
b = AND256M(b, bs[4] + w);
c = AND256M(c, bs[7] + w);
a = AND256M(a, bs[2] + w);
b = AND256M(b, bs[5] + w);
c = AND256M(c, bs[8] + w);
return _mm256_and_si256(_mm256_and_si256(a, b), c);
}
template<int KK>
__attribute__((target("avx2,popcnt")))
static inline __m256i and_tree_lin(const u64 *const *bs, u32 w) {
__m256i a = LDU256((bs[0] + w));
for (int d = 1; d < KK; d++) a = AND256M(a, bs[d] + w);
return a;
}
template<int KK>
__attribute__((target("avx2,popcnt")))
#define NIDWIDE_CORR(NN,KK_,DS_,RR_,BD_,QQ_) ({ \
u32 _acc = 0; const u32 *_ods = s_ord[DS_]; \
for (u32 _q = 65535u; _q < (RR_); _q++) { \
u32 _p = _ods[_q]; int _ok = 1; \
for (int _d = 0; _d < (KK_); _d++) { \
if (_d == (int)(DS_)) continue; \
u32 _b = (BD_)[_d]; u32 _pend = (_b < (QQ_)) ? FPOS(_d, _b) : (NN); \
if (!(s_gt[_d][_p] < _pend)) { _ok = 0; break; } } \
_acc += (u32)_ok; } \
_acc; })
__attribute__((optimize("O2","no-tree-vectorize")))
static u32 and_popcount_range(const u64 *const *bs, u32 Wr, u32 rem) {
const __m256i lm = _mm256_set1_epi8(0x0f);
const __m256i lk = _mm256_setr_epi8(0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4);
const __m256i z = _mm256_setzero_si256();
__m256i tot = z, acc = z;
u32 w = 0, cnt = 0, total = 0;
for (; w + 8 <= Wr; w += 8) {
__m256i a0 = AND_TREE(bs, w);
__m256i a1 = AND_TREE(bs, w + 4);
{
__m256i lo = _mm256_and_si256(a0, lm);
__m256i hi = _mm256_and_si256(_mm256_srli_epi16(a0, 4), lm);
acc = _mm256_add_epi8(acc, _mm256_add_epi8(_mm256_shuffle_epi8(lk, lo), _mm256_shuffle_epi8(lk, hi)));
if (++cnt == 31) { tot = _mm256_add_epi64(tot, _mm256_sad_epu8(acc, z)); acc = z; cnt = 0; }
}
{
__m256i lo = _mm256_and_si256(a1, lm);
__m256i hi = _mm256_and_si256(_mm256_srli_epi16(a1, 4), lm);
acc = _mm256_add_epi8(acc, _mm256_add_epi8(_mm256_shuffle_epi8(lk, lo), _mm256_shuffle_epi8(lk, hi)));
if (++cnt == 31) { tot = _mm256_add_epi64(tot, _mm256_sad_epu8(acc, z)); acc = z; cnt = 0; }
}
}
for (; w + 4 <= Wr; w += 4) {
__m256i a = AND_TREE(bs, w);
__m256i lo = _mm256_and_si256(a, lm);
__m256i hi = _mm256_and_si256(_mm256_srli_epi16(a, 4), lm);
acc = _mm256_add_epi8(acc, _mm256_add_epi8(_mm256_shuffle_epi8(lk, lo), _mm256_shuffle_epi8(lk, hi)));
if (++cnt == 31) { tot = _mm256_add_epi64(tot, _mm256_sad_epu8(acc, z)); acc = z; cnt = 0; }
}
tot = _mm256_add_epi64(tot, _mm256_sad_epu8(acc, z));
total = hsum256(tot);
for (; w < Wr; w++) {
u64 v = bs[0][w];
for (int d = 1; d < KK; d++) v &= bs[d][w];
total += (u32)__builtin_popcountll(v);
}
if (rem) {
u64 v = bs[0][Wr];
for (int d = 1; d < KK; d++) v &= bs[d][Wr];
total += (u32)__builtin_popcountll(v & ((1ull << rem) - 1));
}
return total;
}
template<int KK>
__attribute__((optimize("O3","no-jump-tables","no-split-loops","align-loops=32")))
__attribute__((target("avx2,popcnt")))
__attribute__((flatten)) static void query_group(u32 N, u32 *out, u32 ds, u32 q0, u32 q1, u32 Q, u32 W) {
const int k = KK;
const int K1 = KK - 1;
u32 *qo = s_qord, *qt = s_tmp;
#if MF_ASCR
const u32 d1 = (ds == 0) ? 1u : 0u;
const u32 e1 = (d1 < ds) ? d1 : d1 - 1;
{
u32 *cntv = s_cntv;
for (u32 v = 0; v <= Q; v++) cntv[v] = 0;
for (u32 qi = q0; qi < q1; qi++) {
u32 bb=qo[qi]>>20;
cntv[bb + 1]++;
}
{ u32 ac = q0; for (u32 v = 0; v <= Q; v++) { u32 c = cntv[v]; cntv[v] = ac; ac += c; } }
for (u32 qi = q0; qi < q1; qi++) {
u32 packed=qo[qi],id=packed&0xfffffu,bb=packed>>20;
u32 pos=cntv[bb+1]++;
qt[pos]=id;s_bka[pos]=bb;
}
{ u32 *swp = qo; qo = qt; qt = swp; }
}
#else
const u32 d1 = 0, e1 = 0;
#endif
if (g_lexsort) {
u32 *cntv = s_cntv;
for (int dd = k - 1; dd >= 0; dd--) {
if (dd == ds) continue;
for (u32 v = 0; v <= Q; v++) cntv[v] = 0;
for (u32 qi = q0; qi < q1; qi++) cntv[s_bdT[(size_t)dd * N + qo[qi]] + 1]++;
{ u32 ac = q0; for (u32 v = 0; v <= Q; v++) { u32 c = cntv[v]; cntv[v] = ac; ac += c; } }
for (u32 qi = q0; qi < q1; qi++) {
u32 id = qo[qi];
if (qi + 16 < q1) __builtin_prefetch((const char *)(s_bdT + (size_t)dd * N + qo[qi + 16]), 3);
qt[cntv[s_bdT[(size_t)dd * N + id] + 1]++] = id;
}
{ u32 *swp = qo; qo = qt; qt = swp; }
}
}
#ifdef PF_DIST
for (u32 qi = q0; qi < q0 + PF_DIST && qi + PF_DIST < q1; qi++) {
u32 j = qo[qi + PF_DIST];
const u8 *bdn = s_bd + (size_t)j * MAXK;
for (int e = 0; e < K1; e++) {
int d = (e < ds) ? e : e + 1;
const char *pp = (const char *)(s_bs + (g_plen_on ? s_pofs[(size_t)e * MAXQ + bdn[d]] : ((size_t)e * (Q + 1) + bdn[d]) * W));
_mm_prefetch(pp, _MM_HINT_T0);
_mm_prefetch(pp + 64, _MM_HINT_T0);
_mm_prefetch(pp + 128, _MM_HINT_T0);
}
}
#endif
#if MF_ASCR
{
u32 qi = q0;
while (qi < q1) {
u32 b1 = s_bka[qi];
u32 qe;
if (!g_lexsort) qe = s_cntv[b1 + 1];
else { qe = qi + 1; while (qe < q1 && s_bka[qe] == b1) qe++; }
const u64 *bp1 = g_plen_on ? (s_bs + s_pofs[(size_t)e1 * MAXQ + b1])
: (s_bs + ((size_t)e1 * (Q + 1) + b1) * W);
for (u32 qq = qi; qq < qe; qq++) {
u32 i = qo[qq];
const u8 *bd = s_bd + (size_t)i * MAXK;
#if MF_PFA > 0
{
u32 qj = qq + MF_PFA;
if (qj < qe) {
u32 j = qo[qj];
_mm_prefetch((const char *)(s_bd + (size_t)j * MAXK), _MM_HINT_NTA);
_mm_prefetch((const char *)(s_gc + j), _MM_HINT_NTA);
}
}
#endif
const u32 R = s_gc[i].g >> 4;
u32 cnt = 0;
if (R && !g_skip_and) {
const u64 *bp[MAXK];
for (int e = 0; e < K1; e++) {
if (e == (int)e1) bp[e] = bp1;
else { int d = (e < ds) ? e : e + 1;
bp[e] = g_plen_on ? (s_bs + s_pofs[(size_t)e * MAXQ + bd[d]])
: (s_bs + ((size_t)e * (Q + 1) + bd[d]) * W); }
}
if (g_nidwide & (R > 65535u)) cnt = and_popcount_range<KK - 1>(bp, 1023u, 63u) + NIDWIDE_CORR(N, k, ds, R, bd, Q);
else cnt = and_popcount_range<KK - 1>(bp, R >> 6, R & 63u);
}
s_gc[i].cnt=(u32)(u16)cnt;
}
qi = qe;
}
}
#else
for (u32 qi = q0; qi < q1; qi++) {
u32 i = qo[qi];
const u8 *bd = s_bd + (size_t)i * MAXK;
#if MF_PFA > 0
{
u32 qj = qi + MF_PFA;
if (qj < q1) {
u32 j = qo[qj];
_mm_prefetch((const char *)(s_bd + (size_t)j * MAXK), _MM_HINT_T0);
_mm_prefetch((const char *)(s_gc + j), _MM_HINT_T0);
}
}
#endif
#ifdef PF_DIST
if (qi + PF_DIST < q1) {
u32 j = qo[qi + PF_DIST];
const u8 *bdn = s_bd + (size_t)j * MAXK;
for (int e = 0; e < K1; e++) {
int d = (e < ds) ? e : e + 1;
const char *pp = (const char *)(s_bs + (g_plen_on ? s_pofs[(size_t)e * MAXQ + bdn[d]] : ((size_t)e * (Q + 1) + bdn[d]) * W));
_mm_prefetch(pp, _MM_HINT_T0);
_mm_prefetch(pp + 64, _MM_HINT_T0);
}
}
#endif
const u32 R = s_gc[i].g >> 4;
u32 cnt = 0;
if (R && !g_skip_and) {
const u64 *bp[MAXK];
for (int e = 0; e < K1; e++) {
int d = (e < ds) ? e : e + 1;
bp[e] = g_plen_on ? (s_bs + s_pofs[(size_t)e * MAXQ + bd[d]])
: (s_bs + ((size_t)e * (Q + 1) + bd[d]) * W);
#ifdef DBG_PLEN
if (g_plen_on) {
u32 need = (R >> 6) + ((R & 63) ? 1 : 0);
if (need > s_plen[(size_t)e * MAXQ + bd[d]])
printf("DBG ds=%d e=%d d=%d b=%u R=%u need=%u len=%u\n", ds, e, d, bd[d], R, need, s_plen[(size_t)e * MAXQ + bd[d]]);
}
#endif
}
if (g_nidwide & (R > 65535u)) cnt = and_popcount_range<KK - 1>(bp, 1023u, 63u) + NIDWIDE_CORR(N, k, ds, R, bd, Q);
else cnt = and_popcount_range<KK - 1>(bp, R >> 6, R & 63u);
}
s_gc[i].cnt=(u32)(u16)cnt;
}
#endif
}
template<int D> __attribute__((target("avx2"))) static inline u32 fringe_high_exact(__m256i q,const u32*p){
if constexpr(D>=8){ constexpr int other=17-D; return p[other]<(u32)_mm_extract_epi32(_mm256_castsi256_si128(q),other-8); }
else return (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(q,LDU256(p+8)),_mm256_set1_epi32(-1));
}
template<int KK, int D>
__attribute__((target("avx2,popcnt")))
static void fr_dim(u32 N,u32*out,u32 B,u32*const avpool){
const int k=KK;
u32 exmask = 0;
for (int e = 0; e < D; e++) exmask |= 1u << e;
u32 hiA[8], hiAh[8];
for (int e = 0; e < 8; e++) hiA[e] = ((exmask >> e) & 1u) ? 0u : 0x7FFFFFFFu;
for (int e = 8; e < 16; e++) hiAh[e - 8] = ((exmask >> e) & 1u) ? 0u : 0x7FFFFFFFu;
const __m256i notexlo = LDU256(hiA);
const __m256i notexloh = LDU256(hiAh);
const __m256i all8 = _mm256_set1_epi32(-1);
int amb_n = 0;
const u32 *const odd = s_ord[D];
const u8 *const splane = s_sig + (size_t)D * k * MF_SPL;
const u32 *const sdmpd = s_sdmp[D];
const u32 last_bucket=(N-1u)/B;
for(u32 bucket=0;bucket<=last_bucket;++bucket){
const u32 lo=FPOS(D,bucket),end=bucket==last_bucket?N:FPOS(D,bucket+1);
for(u32 rank=lo;rank<end;++rank){
const u32 i=odd[rank];
if((s_gc[i].g&15u)==(u32)D)continue;
#if MF_PFB3 > 0
{
u32 qj=rank+MF_PFB3;
if(qj<end){
u32 j=odd[qj];
_mm_prefetch((const char *)(s_pm + (size_t)j * STRIDE), _MM_HINT_T0);
_mm_prefetch((const char *)(s_gt[D] + j), _MM_HINT_T0);
if constexpr(D!=0) _mm_prefetch((const char *)(avpool + (size_t)j * 8u), _MM_HINT_T0);
if constexpr(D==9)_mm_prefetch((const char *)(s_av8+j),_MM_HINT_T0);
_mm_prefetch((const char *)(s_gc + j), _MM_HINT_T0);
}
}
#endif
const u32 hi = s_gt[D][i];
if (lo >= hi) continue;
const u32 *rec = s_pm + (size_t)i * STRIDE;
const u32 *Avp = avpool + (size_t)i * 8u;
__m256i qr = _mm256_or_si256(_mm256_load_si256((const __m256i *)rec), khi8v);
__m256i qT, qTh;
if (D == 0) {
qT = qr;
} else {
__m256i Avm = _mm256_or_si256(LDU256(Avp), notexlo);
qT = _mm256_min_epi32(qr, Avm);
}
if (k > 8) {
__m256i qrh = _mm256_or_si256(LDU256((rec + 8)), khi8hv);
if ((int)D <= 8) {
qTh = qrh;
} else {
__m256i Avmh = _mm256_or_si256(_mm256_set1_epi32((int)s_av8[i]), notexloh);
qTh = _mm256_min_epi32(qrh, Avmh);
}
} else {
qTh = all8;
}
u32 add = 0;
const u32 *c0 = sdmpd ? (sdmpd + (size_t)lo * g_KS) : 0;
if (g_use_filt) {
const u32 w0 = lo >> 6;
const u32 nw = ((hi - 1) >> 6) - w0 + 1;
u64 *fb = s_fbuf;
const u64 wcs = (u64)N / g_Qc + 1;
const u32 FW = g_fbm_W;
int first = 1;
#if MF_FR_NOREAD
first = 0;
for (u32 w = 0; w < nw; w++) fb[w] = 0;
#endif
for (int e = 0; e < k; e++) {
if (e == D) continue;
u32 c = (u32)((u64)rec[e] / wcs) + 1;
if (c > g_Qc) c = g_Qc;
const u64 *row = s_fbm + ((size_t)(D * k + e) * (g_Qc + 1) + c) * FW + w0;
if (first) { for (u32 w = 0; w < nw; w++) fb[w] = row[w]; first = 0; }
else { for (u32 w = 0; w < nw; w++) fb[w] &= row[w]; }
}
fb[0] &= ~0ull << (lo & 63);
u32 r2 = hi & 63u;
if (r2) fb[nw - 1] &= (1ull << r2) - 1;
for (u32 w = 0; w < nw; w++) {
u64 vv = fb[w];
#if MF_FR_NOCAND
vv = 0;
#endif
while (vv) {
int t = __builtin_ctzll(vv);
vv &= vv - 1;
u32 j = ((w0 + w) << 6) + (u32)t;
const u32 *cp = c0 ? (c0 + (size_t)(j - lo) * g_KS) : (s_pm + (size_t)s_ord[D][j] * STRIDE);
__m256i pv = LDU256(cp);
u32 ok = (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, pv), all8);
if (k > 8) {
ok &= fringe_high_exact<D>(qTh,cp);
}
add += ok;
}
}
add_out16(i,add);
continue;
}
if (g_sig_on && (hi - lo) >= 2) {
__m256i qsb[16];
{
const __m256i shv = _mm256_set1_epi32((int)g_sigsh);
const __m256i oneb = _mm256_set1_epi8(1);
const __m256i svl = _mm256_subs_epu8(_mm256_srli_epi32(_mm256_mullo_epi32(qT,_mm256_set1_epi32(g_sigmul)),23),oneb);
const __m256i svh = _mm256_subs_epu8(_mm256_srli_epi32(_mm256_mullo_epi32(qTh,_mm256_set1_epi32(g_sigmul)),23),oneb);
const __m256i sl_lo = _mm256_permute2x128_si256(svl, svl, 0x00);
const __m256i sl_hi = _mm256_permute2x128_si256(svl, svl, 0x11);
const __m256i sh_lo = _mm256_permute2x128_si256(svh, svh, 0x00);
for (int e = 0; e < k; e++) {
if (e == (int)D) { qsb[e] = _mm256_set1_epi8((char)0xFF); continue; }
const __m256i src = (e < 4) ? sl_lo : ((e < 8) ? sl_hi : sh_lo);
qsb[e] = _mm256_shuffle_epi8(src, _mm256_load_si256((const __m256i *)mask4[e & 3]));
}
}
u32 aj = lo, aacc = 0, aexact = 0;
const int ajlim = (int)hi - 32;
for (; (int)aj <= ajlim; aj += 32) {
__m256i ac = _mm256_setzero_si256();
{
for (int e = 0; e < k; e++) {
if (e == (int)D) continue;
__m256i cv = LDU256((splane + (size_t)e * MF_SPL + aj));
ac = _mm256_or_si256(ac, _mm256_subs_epu8(cv, qsb[e]));
}
}
__m256i lt = _mm256_cmpeq_epi8(ac, _mm256_setzero_si256());
u32 ltm = (u32)_mm256_movemask_epi8(lt);
u32 amb = (u32)_mm256_movemask_epi8(_mm256_cmpeq_epi8(ac,_mm256_set1_epi8(1)));
aacc += (u32)__builtin_popcount(ltm);
while (amb) {
int t = __builtin_ctz(amb); amb &= amb - 1;
const u32 *cp = c0 ? (c0 + (size_t)(aj + (u32)t - lo) * g_KS) : (s_pm + (size_t)odd[aj + (u32)t] * STRIDE);
if (amb_n < AMBD_CAP) {
s_abi[amb_n] = i;
s_abp[amb_n] = cp;
_mm256_store_si256(&s_abqT[amb_n], qT);
if constexpr(D>=8){const u32 last=(u32)_mm_extract_epi32(_mm256_castsi256_si128(qTh),9-D);__builtin_memcpy(&s_abqTh[amb_n],&last,4);}else if(k>8)_mm256_store_si256(&s_abqTh[amb_n],qTh);
amb_n++;
} else {
__m256i pv = LDU256(cp);
u32 okl = (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, pv), all8);
if (k > 8) {
okl &= fringe_high_exact<D>(qTh,cp);
}
aacc += okl;
}
}
}
{
u32 r = hi - aj;
if (r) {
u32 base, lk;
if (hi >= 32u) { base = hi - 32u; lk = 32u - r; }
else { base = 0u; lk = lo; }
u32 kmask = ((r >= 32u) ? 0xFFFFFFFFu : ((1u << r) - 1u)) << lk;
__m256i ac = _mm256_setzero_si256();
{
for (int e = 0; e < k; e++) {
if (e == (int)D) continue;
__m256i cv = LDU256((splane + (size_t)e * MF_SPL + base));
ac = _mm256_or_si256(ac, _mm256_subs_epu8(cv, qsb[e]));
}
}
__m256i lt = _mm256_cmpeq_epi8(ac, _mm256_setzero_si256());
u32 ltm = ((u32)_mm256_movemask_epi8(lt)) & kmask;
u32 amb = (u32)_mm256_movemask_epi8(_mm256_cmpeq_epi8(ac,_mm256_set1_epi8(1))) & kmask;
aacc += (u32)__builtin_popcount(ltm);
while (amb) {
int t = __builtin_ctz(amb); amb &= amb - 1;
const u32 *cp = c0 ? (c0 + (size_t)(base + (u32)t - lo) * g_KS) : (s_pm + (size_t)odd[base + (u32)t] * STRIDE);
if (amb_n < AMBD_CAP) {
s_abi[amb_n] = i;
s_abp[amb_n] = cp;
_mm256_store_si256(&s_abqT[amb_n], qT);
if constexpr(D>=8){const u32 last=(u32)_mm_extract_epi32(_mm256_castsi256_si128(qTh),9-D);__builtin_memcpy(&s_abqTh[amb_n],&last,4);}else if(k>8)_mm256_store_si256(&s_abqTh[amb_n],qTh);
amb_n++;
} else {
__m256i pv = LDU256(cp);
u32 okl = (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, pv), all8);
if (k > 8) {
okl &= fringe_high_exact<D>(qTh,cp);
}
aacc += okl;
}
}
}
}
add = aacc;
} else if (c0) {
if (k <= 8) {
const u32 *c = c0;
u32 a0 = 0, a1 = 0, a2 = 0, a3 = 0;
u32 j = lo;
for (; j + 4 <= hi; j += 4) {
__m256i p0 = LDU256((c));
__m256i p1 = LDU256((c + g_KS));
__m256i p2 = LDU256((c + 2 * g_KS));
__m256i p3 = LDU256((c + 3 * g_KS));
a0 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p0), all8);
a1 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p1), all8);
a2 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p2), all8);
a3 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p3), all8);
c += 4 * g_KS;
}
for (; j < hi; j++, c += g_KS) {
__m256i pv = LDU256(c);
a0 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, pv), all8);
}
add = a0 + a1 + a2 + a3;
} else {
const u32 *c = c0;
u32 a0 = 0, a1 = 0, a2 = 0, a3 = 0;
u32 j = lo;
for (; j + 4 <= hi; j += 4) {
__m256i p0 = LDU256((c));
__m256i p1 = LDU256((c + g_KS));
__m256i p2 = LDU256((c + 2 * g_KS));
__m256i p3 = LDU256((c + 3 * g_KS));
__m256i h0 = LDU256((c + 8));
__m256i h1 = LDU256((c + g_KS + 8));
__m256i h2 = LDU256((c + 2 * g_KS + 8));
__m256i h3 = LDU256((c + 3 * g_KS + 8));
a0 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p0), all8) & (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qTh, h0), all8);
a1 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p1), all8) & (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qTh, h1), all8);
a2 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p2), all8) & (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qTh, h2), all8);
a3 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, p3), all8) & (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qTh, h3), all8);
c += 4 * g_KS;
}
for (; j < hi; j++, c += g_KS) {
__m256i pv = LDU256(c);
__m256i pvh = LDU256((c + 8));
a0 += (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, pv), all8) &
(u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qTh, pvh), all8);
}
add = a0 + a1 + a2 + a3;
}
} else {
for (u32 j = lo; j < hi; j++) {
const u32 *c = s_pm + (size_t)odd[j] * STRIDE;
__m256i pv = _mm256_load_si256((const __m256i *)c);
u32 ok = (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qT, pv), all8);
if (k > 8) {
ok &= fringe_high_exact<D>(qTh,c);
}
add += ok;
}
}
add_out16(i,add);
}
}
for (int z = 0; z < amb_n; z++) {
if (z + 12 < amb_n) __builtin_prefetch(s_abp[z + 12], 0, 0);
const u32 *cp = s_abp[z];
__m256i pv = LDU256(cp);
__m256i qv = _mm256_load_si256(&s_abqT[z]);
u32 ok = (u32)_mm256_testc_si256(_mm256_cmpgt_epi32(qv, pv), all8);
if constexpr(D>=8){u32 last;__builtin_memcpy(&last,&s_abqTh[z],4);ok &= cp[17-D]<last;}
else if(k>8)ok &= fringe_high_exact<D>(_mm256_load_si256(&s_abqTh[z]),cp);
add_out16(s_abi[z],ok);
}
}
template<int KK>
__attribute__((target("avx2,popcnt")))
static void dimension_major_fringe(u32 N,u32*out,u32 B){
if (g_skip_fringe) return;
u32 *const avpool = s_avpool;
fr_dim<KK,0>(N,out,B,avpool);
fr_dim<KK,1>(N,out,B,avpool);
fr_dim<KK,2>(N,out,B,avpool);
fr_dim<KK,3>(N,out,B,avpool);
fr_dim<KK,4>(N,out,B,avpool);
fr_dim<KK,5>(N,out,B,avpool);
fr_dim<KK,6>(N,out,B,avpool);
fr_dim<KK,7>(N,out,B,avpool);
fr_dim<KK,8>(N,out,B,avpool);
fr_dim<KK,9>(N,out,B,avpool);
}
__attribute__((target("avx2")))
static void solve_mf(u32 N, const unsigned **x, u32 *out, int k) {
const u32 W = ((N + 63) / 64 + 7u) & ~7u;
g_W = W;
#ifdef MF_SKIP_AND
g_skip_and = 1;
#endif
#ifdef MF_FILT
g_use_filt = 1;
#endif
#ifdef MF_NOFILT
g_use_filt = 0;
#endif
#ifdef MF_Q
g_Q = MF_Q; g_B = (u32)((N + (MF_Q) - 1) / (MF_Q));
#endif
#ifdef MF_FILT
g_use_filt = 1;
#endif
#ifdef MF_NOFILT
g_use_filt = 0;
#endif
#ifdef MF_SKIP_FRINGE
g_skip_fringe = 1;
#endif
if (!g_Q) {
u64 r = (u64)N, s2 = 0;
while (s2 * s2 < r) s2++;
u64 overhead = (u64)(5 * k + 21) * N * 4;
overhead += (u64)k * k * 4 * N;
overhead += (u64)k * k * MF_SPL;
overhead += (u64)N * ((k <= 8) ? 8u : (u32)k) * 4 * k;
u64 budget = ((u64)MF_BUDGETMB << 20);
if (budget > overhead + ((u64)64 << 20)) budget -= overhead; else budget = (u64)64 << 20;
#if MF_PLEN
static const u32 kfill[7] = {72, 67, 62, 58, 54, 50, 46};
u64 perfill = ((u64)(k - 1) * W * 8) * kfill[k - 4] / 100;
#else
u64 perfill = (u64)(k - 1) * W * 8;
#endif
u64 Qmem = budget / (perfill ? perfill : 1);
if (Qmem < 8) Qmem = 8;
static const u32 kscale[7] = {82, 91, 100, 108, 115, 122, 129};
u32 q = (u32)((s2 * MF_QCOEF + 99) / 100);
q = (u32)(((u64)q * kscale[k - 4] + 99) / 100);
if ((u64)q > Qmem) q = (u32)Qmem;
if (q > N) q = N;
g_Q = q;
g_B = (N + q - 1) / q;
}
const u32 Q = g_Q, B = g_B;
g_MS = (Q + 1 <= MAXQ) ? (Q + 1) : MAXQ;
if (g_hug) {
t16h_hugify(s_ord, sizeof(s_ord)); t16h_hugify(s_gt, sizeof(s_gt));
t16h_hugify(s_pm, sizeof(s_pm)); t16h_hugify(s_bd, sizeof(s_bd));
t16h_hugify(s_bdT, sizeof(s_bdT)); t16h_hugify(s_pos, sizeof(s_pos));
t16h_hugify(s_posp, sizeof(s_posp)); t16h_hugify(s_bval, sizeof(s_bval));
t16h_hugify(s_maxr, sizeof(s_maxr)); t16h_hugify(s_bka, sizeof(s_bka));
t16h_hugify(s_bks, sizeof(s_bks)); t16h_hugify(s_bkt, sizeof(s_bkt));
t16h_hugify(s_ascr, sizeof(s_ascr)); t16h_hugify(s_facc, sizeof(s_facc));
t16h_hugify(s_nid, sizeof(s_nid)); t16h_hugify(s_qord, sizeof(s_qord));
t16h_hugify(s_tmp, sizeof(s_tmp)); t16h_hugify(s_gc, sizeof(s_gc));
}
const u64 bmag = ((1ull << 40) + B - 1) / B;
#if MF_PLEN
g_plen_on = 1;
#endif
#if MF_WTRIM
u32 Wpool = W;
#else
const u32 Wpool = W;
#endif
#if MF_FILTAUTO
if (!g_use_filt && B >= 400) g_use_filt = 1;
#endif
if (g_use_filt && (u64)k * k * (g_Qc + 1) * W * 8 > ((u64)700 << 20)) g_use_filt = 0;
#if !MF_FILTAUTO
g_use_filt = 0;
#endif
{
int lo8[8], hi8[8];
for (int e = 0; e < 8; e++) lo8[e] = (e < k) ? 0 : 0x7FFFFFFF;
for (int e = 0; e < 8; e++) hi8[e] = (8 + e < k) ? 0 : 0x7FFFFFFF;
khi8v = LDU256(lo8);
khi8hv = LDU256(hi8);
}
const int K1 = k - 1;
for (int d = 0; d < k; d++) {
const unsigned *xd = x[d];
u32 *od = s_ord[d];
u32* ct=s_pk32;u8* hc=s_hist8;
for(u32 i=0;i<=N;i++)hc[i]=0;
u32 qsh_=0; while(((u64)1u<<qsh_)*8u < (u64)N) qsh_++;
u32 qcnt_[8]={0,0,0,0,0,0,0,0};
for(u32 i=0;i<N;i++){
u32 v0=xd[i]; u32 v=(v0<N)?v0:0u; hc[v]++;
u32 s_=v>>qsh_; u32 p_=qcnt_[s_]++;
s_fpl[(size_t)s_*N+p_]=((u64)v<<32)|(u64)i;
}
u32 sum=0, pi=0;
const __m256i last16=_mm256_set1_epi16(0x0f0e);
for(;pi+16<=N+1;pi+=16){
__m256i raw=_mm256_cvtepu8_epi16(_mm_loadu_si128((const __m128i*)(hc+pi)));
__m256i p=_mm256_add_epi16(raw,_mm256_slli_si256(raw,2));
p=_mm256_add_epi16(p,_mm256_slli_si256(p,4));
p=_mm256_add_epi16(p,_mm256_slli_si256(p,8));
p=_mm256_add_epi16(p,_mm256_shuffle_epi8(_mm256_permute2x128_si256(p,p,0x08),last16));
__m256i ex=_mm256_sub_epi16(p,raw),base=_mm256_set1_epi32(sum);
_mm256_storeu_si256((__m256i*)(ct+pi),_mm256_add_epi32(base,_mm256_cvtepu16_epi32(_mm256_castsi256_si128(ex))));
_mm256_storeu_si256((__m256i*)(ct+pi+8),_mm256_add_epi32(base,_mm256_cvtepu16_epi32(_mm256_extracti128_si256(ex,1))));
sum+=(u32)_mm_extract_epi16(_mm256_extracti128_si256(p,1),7);
}
for(;pi<=N;pi++){u32 c=hc[pi];ct[pi]=sum;sum+=c;}
bool packed=(sum==N);
if(!packed){
for(u32 i=0;i<=N;i++)s_pk[i]=0;
for(u32 i=0;i<N;i++){u32 v=xd[i];s_pk[v<N?v:0]++;}
u64 st=0;for(u32 i=0;i<=N;i++){u64 c=s_pk[i];s_pk[i]=(st<<32)|st;st+=c;}
}
u32 *gt=s_gt[d];
auto scatter=[&](auto use32){
if(g_use_filt){
u32* pp=s_pos[d];
for(u32 i=0;i<N;i++){
u32 v=xd[i];if(v>=N)v=0;
u32 q,st,num;
if constexpr(decltype(use32)::value){
u32 w=ct[v];st=w&0xfffffu;q=st+(w>>20);ct[v]=w+(1u<<20);
num=(ct[v+1]&0xfffffu)-1u;
}else{
u64 w=s_pk[v];q=(u32)w;st=(u32)(w>>32);s_pk[v]=w+1;
num=(u32)(s_pk[v+1]>>32)-1u;
}
od[q]=i;
retained_rank16[d][i]=(u16)(q < 65535u ? q : 65535u);
pp[i]=q;
gt[i]=st;if(num>N)num=N;
u32 bb=(u32)(((u64)num*bmag)>>40);
s_bdT[(size_t)d*N+i]=(bb>Q-1?Q-1:(u8)bb);
}
}else{
if constexpr(decltype(use32)::value){
const u32 NS=8u;
for(u32 s_=0;s_<NS;s_++){
u32 e_=qcnt_[s_];
for(u32 p_=0;p_<e_;p_++){
u64 w_=s_fpl[(size_t)s_*N+p_];
u32 i=(u32)w_, v=(u32)(w_>>32);
u32 q,st,num;
u32 w=ct[v];st=w&0xfffffu;q=st+(w>>20);ct[v]=w+(1u<<20);
num=(ct[v+1]&0xfffffu)-1u;
od[q]=i;
retained_rank16[d][i]=(u16)(q < 65535u ? q : 65535u);
gt[i]=st;if(num>N)num=N;
u32 bb=(u32)(((u64)num*bmag)>>40);
s_bdT[(size_t)d*N+i]=(bb>Q-1?Q-1:(u8)bb);
}
}
}else{
for(u32 i=0;i<N;i++){
u32 v=xd[i];if(v>=N)v=0;
u32 q,st,num;
u64 w=s_pk[v];q=(u32)w;st=(u32)(w>>32);s_pk[v]=w+1;
num=(u32)(s_pk[v+1]>>32)-1u;
od[q]=i;
retained_rank16[d][i]=(u16)(q < 65535u ? q : 65535u);
gt[i]=st;if(num>N)num=N;
u32 bb=(u32)(((u64)num*bmag)>>40);
s_bdT[(size_t)d*N+i]=(bb>Q-1?Q-1:(u8)bb);
}
}
}
};
if(packed)scatter(std::true_type{});else scatter(std::false_type{});
BVAL(d, 0) = 0; FPOS(d, 0) = 0;
for (u32 b = 1; b < Q; b++) {
u32 pos = b * B < N ? b * B : N - 1;
u32 v = xd[od[pos]];
BVAL(d, b) = v;
u32 gs = pos;
while (gs > 0 && xd[od[gs - 1]] == v) gs--;
FPOS(d, b) = gs;
}
BVAL(d, Q) = 0xFFFFFFFFu; FPOS(d, Q) = 0;
}
u32 bi=0;
if(k==10) for(;bi+8<=N;bi+=8){
__m128i a[10];
for(int d=0;d<10;d++)a[d]=_mm_loadl_epi64((const __m128i*)(s_bdT+(size_t)d*N+bi));
__m128i x0=_mm_unpacklo_epi8(a[0],a[1]), x1=_mm_unpacklo_epi8(a[2],a[3]);
__m128i x2=_mm_unpacklo_epi8(a[4],a[5]), x3=_mm_unpacklo_epi8(a[6],a[7]);
__m128i y0=_mm_unpacklo_epi16(x0,x1), y1=_mm_unpackhi_epi16(x0,x1);
__m128i y2=_mm_unpacklo_epi16(x2,x3), y3=_mm_unpackhi_epi16(x2,x3);
__m128i z0=_mm_unpacklo_epi32(y0,y2), z1=_mm_unpackhi_epi32(y0,y2);
__m128i z2=_mm_unpacklo_epi32(y1,y3), z3=_mm_unpackhi_epi32(y1,y3);
__m128i tail=_mm_unpacklo_epi8(a[8],a[9]);
u8* dst=s_bd+(size_t)bi*MAXK;
_mm_storel_epi64((__m128i*)(dst+0*MAXK),z0);
*(u16*)(dst+0*MAXK+8)=(u16)_mm_extract_epi16(tail,0);
_mm_storel_epi64((__m128i*)(dst+1*MAXK),_mm_srli_si128(z0,8));
*(u16*)(dst+1*MAXK+8)=(u16)_mm_extract_epi16(tail,1);
_mm_storel_epi64((__m128i*)(dst+2*MAXK),z1);
*(u16*)(dst+2*MAXK+8)=(u16)_mm_extract_epi16(tail,2);
_mm_storel_epi64((__m128i*)(dst+3*MAXK),_mm_srli_si128(z1,8));
*(u16*)(dst+3*MAXK+8)=(u16)_mm_extract_epi16(tail,3);
_mm_storel_epi64((__m128i*)(dst+4*MAXK),z2);
*(u16*)(dst+4*MAXK+8)=(u16)_mm_extract_epi16(tail,4);
_mm_storel_epi64((__m128i*)(dst+5*MAXK),_mm_srli_si128(z2,8));
*(u16*)(dst+5*MAXK+8)=(u16)_mm_extract_epi16(tail,5);
_mm_storel_epi64((__m128i*)(dst+6*MAXK),z3);
*(u16*)(dst+6*MAXK+8)=(u16)_mm_extract_epi16(tail,6);
_mm_storel_epi64((__m128i*)(dst+7*MAXK),_mm_srli_si128(z3,8));
*(u16*)(dst+7*MAXK+8)=(u16)_mm_extract_epi16(tail,7);
}
for(;bi<N;bi++){u8* r_=s_bd+(size_t)bi*MAXK;
for(int d=0;d<k;d++)r_[d]=s_bdT[(size_t)d*N+bi];}
{ u32 i=0;
if(k==10)for(;i+8<=N;i+=8){
const __m256i r0=LDU256(x[0]+i);
const __m256i r1=LDU256(x[1]+i);
const __m256i r2=LDU256(x[2]+i);
const __m256i r3=LDU256(x[3]+i);
const __m256i r4=LDU256(x[4]+i);
const __m256i r5=LDU256(x[5]+i);
const __m256i r6=LDU256(x[6]+i);
const __m256i r7=LDU256(x[7]+i);
const __m256i t0=_mm256_unpacklo_epi32(r0,r1);
const __m256i t1=_mm256_unpackhi_epi32(r0,r1);
const __m256i t2=_mm256_unpacklo_epi32(r2,r3);
const __m256i t3=_mm256_unpackhi_epi32(r2,r3);
const __m256i t4=_mm256_unpacklo_epi32(r4,r5);
const __m256i t5=_mm256_unpackhi_epi32(r4,r5);
const __m256i t6=_mm256_unpacklo_epi32(r6,r7);
const __m256i t7=_mm256_unpackhi_epi32(r6,r7);
const __m256i u0=_mm256_unpacklo_epi64(t0,t2);
const __m256i u1=_mm256_unpackhi_epi64(t0,t2);
const __m256i u2=_mm256_unpacklo_epi64(t1,t3);
const __m256i u3=_mm256_unpackhi_epi64(t1,t3);
const __m256i u4=_mm256_unpacklo_epi64(t4,t6);
const __m256i u5=_mm256_unpackhi_epi64(t4,t6);
const __m256i u6=_mm256_unpacklo_epi64(t5,t7);
const __m256i u7=_mm256_unpackhi_epi64(t5,t7);
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+0)*STRIDE),_mm256_permute2x128_si256(u0,u4,0x20));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+1)*STRIDE),_mm256_permute2x128_si256(u1,u5,0x20));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+2)*STRIDE),_mm256_permute2x128_si256(u2,u6,0x20));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+3)*STRIDE),_mm256_permute2x128_si256(u3,u7,0x20));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+4)*STRIDE),_mm256_permute2x128_si256(u0,u4,0x31));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+5)*STRIDE),_mm256_permute2x128_si256(u1,u5,0x31));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+6)*STRIDE),_mm256_permute2x128_si256(u2,u6,0x31));
_mm256_store_si256((__m256i*)(s_pm+(size_t)(i+7)*STRIDE),_mm256_permute2x128_si256(u3,u7,0x31));
const __m256i hi8=LDU256(x[8]+i),hi9=LDU256(x[9]+i);
const __m256i hp0=_mm256_unpacklo_epi32(hi8,hi9),hp1=_mm256_unpackhi_epi32(hi8,hi9);
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+0)*STRIDE+8),_mm256_castsi256_si128(hp0));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+1)*STRIDE+8),_mm_srli_si128(_mm256_castsi256_si128(hp0),8));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+2)*STRIDE+8),_mm256_castsi256_si128(hp1));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+3)*STRIDE+8),_mm_srli_si128(_mm256_castsi256_si128(hp1),8));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+4)*STRIDE+8),_mm256_extracti128_si256(hp0,1));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+5)*STRIDE+8),_mm_srli_si128(_mm256_extracti128_si256(hp0,1),8));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+6)*STRIDE+8),_mm256_extracti128_si256(hp1,1));
_mm_storel_epi64((__m128i*)(s_pm+(size_t)(i+7)*STRIDE+8),_mm_srli_si128(_mm256_extracti128_si256(hp1,1),8));
}
for(;i<N;++i){u32 *p=s_pm+(size_t)i*STRIDE;for(int d=0;d<k;++d)p[d]=x[d][i];}
}
{
u32 nn = N - 1; u32 sh = 0;
while (nn > 255u) { nn >>= 1; sh++; }
g_sigsh = sh; g_sigmul=N>1?(u32)(((u64)255<<23)/(N-1)):0;
size_t need = (size_t)k * k * MF_SPL;
static u8 *sigpool = 0; static size_t sigcap = 0;
if (need > ((size_t)220 << 20) || (size_t)N + 32 > MF_SPL) { sigpool = 0; sigcap = 0; }
else if (need > sigcap) { sigpool = (u8 *)pool_alloc(need); sigcap = sigpool ? need : 0; }
if (sigpool) {
s_sig = sigpool;
g_sig_on = 1;
g_sig_merged = 0;
}
}
#if MF_NOFILTB
g_use_filt = 0;
#endif
#if MF_FB3
if (g_use_filt) {
u32 Qc = g_Qc;
u64 wc = (u64)N / Qc + 1;
for (int e = 0; e < k; e++) {
const unsigned *xe = x[e];
const u32 *pe = s_ord[e];
u32 ptr_ = 0;
u32 *bn = s_bnde + (size_t)e * (MAXQ + 2);
for (u32 c = 0; c <= Qc; c++) {
u64 v = (u64)c * wc;
if (v > 0xFFFFFFFFull) v = 0xFFFFFFFFull;
while (v && ptr_ < N && (u64)xe[pe[ptr_]] < v) ptr_++;
bn[c] = ptr_;
}
}
}
#endif
if (g_use_filt) {
u32 Qc = g_Qc;
u64 wc = (u64)N / Qc + 1;
size_t need2 = (size_t)k * k * (Qc + 1) * W * sizeof(u64);
static u64 *fpool = 0; static size_t fcap = 0;
if (need2 > fcap) { fpool = (u64 *)pool_alloc(need2 + 4096); fcap = need2; }
if (fpool) {
s_fbm = fpool; g_fbm_W = W;
#if MF_FB2
for (int d = 0; d < k; d++)
for (int e = 0; e < k; e++) {
if (e == d) continue;
u64 *b0 = s_fbm + (size_t)(d * k + e) * (Qc + 1) * W;
for (u32 w = 0; w < W; w++) b0[w] = 0;
}
for (int e = 0; e < k; e++) {
const unsigned *xe = x[e];
const u32 *pe = s_ord[e];
int dmap[MAXK], km1 = 0;
for (int d = 0; d < k; d++) if (d != e) dmap[km1++] = d;
for (int i = 0; i < km1; i++) { u64 *a = s_facc + (size_t)i * W; for (u32 w = 0; w < W; w++) a[w] = 0; }
u32 ptr_ = 0;
for (u32 c = 1; c <= Qc; c++) {
u64 v = (u64)c * wc;
if (v > 0xFFFFFFFFull) v = 0xFFFFFFFFull;
while (ptr_ < N && (u64)xe[pe[ptr_]] < v) {
const u32 *pv = s_posp + (size_t)pe[ptr_] * MAXK;
for (int i = 0; i < km1; i++) {
u32 q = pv[dmap[i]];
s_facc[(size_t)i * W + (q >> 6)] |= 1ull << (q & 63);
}
ptr_++;
}
for (int i = 0; i < km1; i++) {
int d = dmap[i];
u64 *dst = s_fbm + ((size_t)(d * k + e) * (Qc + 1) + c) * W;
const u64 *src = s_facc + (size_t)i * W;
#if MF_NT
{ u32 w = 0;
for (; w + 4 <= W; w += 4) _mm256_stream_si256((__m256i *)(dst + w), _mm256_load_si256((const __m256i *)(src + w)));
for (; w < W; w++) dst[w] = src[w]; }
#else
{ u32 w = 0;
for (; w + 4 <= W; w += 4) _mm256_storeu_si256((__m256i *)(dst + w), LDU256((const __m256i *)(src + w)));
for (; w < W; w++) dst[w] = src[w]; }
#endif
}
}
}
#else
for (int d = 0; d < k; d++) {
for (int e = 0; e < k; e++) {
if (e == d) continue;
const unsigned *xe = x[e];
const u32 *pe = s_ord[e];
const u32 *pd = s_pos[d];
u64 *base = s_fbm + (size_t)(d * k + e) * (Qc + 1) * W;
for (u32 w = 0; w < W; w++) base[w] = 0;
u64 *cur = s_acc;
for (u32 w = 0; w < W; w++) cur[w] = 0;
u32 ptr_ = 0;
for (u32 c = 1; c <= Qc; c++) {
#if MF_FB3
u32 pend = s_bnde[(size_t)e * (MAXQ + 2) + c];
#else
u64 v = (u64)c * wc;
if (v > 0xFFFFFFFFull) v = 0xFFFFFFFFull;
u32 pend = ptr_;
{ const unsigned *xe_ = xe; const u32 *pe_ = pe;
while (pend < N && (u64)xe_[pe_[pend]] < v) pend++; }
#endif
while (ptr_ < pend) { u32 q = pd[pe[ptr_]]; cur[q >> 6] |= 1ull << (q & 63); ptr_++; }
u64 *dst = base + (size_t)c * W;
#if MF_NT
{ u32 w = 0;
for (; w + 4 <= W; w += 4) _mm256_stream_si256((__m256i *)(dst + w), _mm256_load_si256((const __m256i *)(cur + w)));
for (; w < W; w++) dst[w] = cur[w]; }
#else
for (u32 w = 0; w < W; w++) dst[w] = cur[w];
#endif
}
}
}
#endif
} else { g_use_filt = 0; }
_mm_sfence();
}
{
size_t needav = (size_t)N * 8u * 4 + 256;
if (needav > s_avcap) {
s_avpool = (u32 *)pool_alloc(needav);
s_avcap = s_avpool ? needav : 0;
}
}
{
size_t mrn = (size_t)MAXK * MAXK * g_MS;
for (size_t z = 0; z < mrn; z++) s_maxr[z] = 0;
}
for(u32 block=0;block<N;block+=8){
const u32 end=(block+8<N)?block+8:N;
alignas(32) u32 fold8[8];
if(k==10 && end-block==8){
__m256i v=_mm256_slli_epi32(_mm256_loadu_si256((const __m256i*)(s_gt[0]+block)),4);
for(unsigned d=1;d<10;++d){
__m256i q=_mm256_or_si256(_mm256_slli_epi32(_mm256_loadu_si256((const __m256i*)(s_gt[d]+block)),4),_mm256_set1_epi32(d));
v=_mm256_min_epu32(v,q);
}
_mm256_store_si256((__m256i*)fold8,v);
}else{
for(u32 i=block;i<end;++i){u32 v=s_gt[0][i]<<4;for(int d=1;d<k;++d){u32 q=(s_gt[d][i]<<4)|(u32)d;if(q<v)v=q;}fold8[i-block]=v;}
}
#pragma GCC unroll 1
for(u32 i=block;i<end;++i){
const u32 best=fold8[i-block]>>4;const int ds=fold8[i-block]&15u;
s_gc[i].g = (best << 4) | (u32)ds;
const u8 *bdv = s_bd + (size_t)i * MAXK;
u32 *av = s_avpool + (size_t)i * 8u;
u32 *mr = s_maxr + ((size_t)ds * MAXK) * g_MS;
if (g_plen_on) {
for (int d = 0; d < 8; d++) {
u32 b = bdv[d];av[d] = s_bval[(size_t)d * g_MS + b];
u32 *mp = mr + (size_t)d * g_MS + b;u32 m0 = *mp;*mp = (m0 > best) ? m0 : best;
}
for(int d=8;d<10;++d){u32 *mp=mr+(size_t)d*g_MS+bdv[d];u32 m0=*mp;*mp=(m0>best)?m0:best;}
} else {
for (int d = 0; d < 8; d++) av[d] = s_bval[(size_t)d * g_MS + bdv[d]];
}
const u32 diag=(u32)ds&7u;av[diag]=ds<8?0x7fffffffu:av[diag];
s_av8[i]=ds==8?0x7fffffffu:s_bval[(size_t)8*g_MS+bdv[8]];
}
}
// Stable fold scatter consumes the original point IDs directly.
{
for (u32 v = 0; v <= (u32)k; v++) s_cntv[v] = 0;
for (u32 i = 0; i < N; i++) s_cntv[(s_gc[i].g & 15u) + 1]++;
{ u32 ac = 0; for (u32 v = 0; v <= (u32)k; v++) { u32 c = s_cntv[v]; s_cntv[v] = ac; ac += c; } }
for (u32 id = 0; id < N; id++) { const u32 ds=s_gc[id].g&15u;
#if MF_ASCR
const u32 d1=ds?0u:1u;const u32 record=id|((u32)s_bdT[(size_t)d1*N+id]<<20);
#else
const u32 record=id;
#endif
s_tmp[s_cntv[ds+1]++]=record; }
for (u32 i = 0; i < N; i++) s_qord[i] = s_tmp[i];
}
u32 gstart[MAXK + 2];
{ gstart[0] = 0; for (int d = 1; d <= k; ++d) gstart[d] = s_cntv[d]; gstart[k + 1] = N; }
#if MF_NOSDMP
g_nosdmp = 1;
#endif
if (!g_nosdmp) {
u32 KS = k;
#if MF_KSPAD
if (k <= 8) KS = 8;
#endif
size_t per = (size_t)N * KS * 4;
size_t lim = (size_t)150 << 20;
if (k >= 9) lim = (size_t)470 << 20;
if (per * k <= lim) {
static u32 *pool = 0; static size_t cap = 0;
if (per * k > cap) { pool = (u32 *)pool_alloc(per * k + 256); cap = per * k; }
if (pool) {
g_KS = KS;
for (int d = 0; d < k; d++) {
s_sdmp[d] = pool + (size_t)d * N * g_KS;
const u32 *od = s_ord[d];
u32 *dst = s_sdmp[d];
const u32 KSx = g_KS;
for (u32 j = 0; j < N; j++) {
#if MF_PFB > 0
if (j + MF_PFB < N) _mm_prefetch((const char *)(s_pm + (size_t)od[j + MF_PFB] * STRIDE), _MM_HINT_T0);
#endif
const u32 *row = s_pm + (size_t)od[j] * STRIDE;
u32 *dp = dst + (size_t)j * KSx;
for (u32 e = 0; e < KSx; e++) dp[e] = (e < (u32)k) ? row[e] : 0u;
if (s_sig) {
u8 *sb = s_sig + (size_t)d * k * MF_SPL;
for (int e = 0; e < k; e++) sb[(size_t)e * MF_SPL + j] = sigfull(row[e]);
}
}
if (s_sig) g_sig_merged = 1;
}
}
}
}
if (s_sig && !g_sig_merged && k==10) {
static u8 cached_signature[(size_t)MAXN*16] __attribute__((aligned(64)));
prepare_cached_signatures(cached_signature,x,N);
for(int d=0;d<k;d++) {
const u32 *od=s_ord[d];
u8 *base=s_sig+(size_t)d*k*MF_SPL;
u32 j=0;
for(;j+8<=N;j+=8) {
if(j+64<N)_mm_prefetch((const char *)(cached_signature+(size_t)od[j+64]*16),_MM_HINT_T0);
__m128i r0=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+0]*16));
__m128i r1=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+1]*16));
__m128i r2=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+2]*16));
__m128i r3=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+3]*16));
__m128i r4=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+4]*16));
__m128i r5=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+5]*16));
__m128i r6=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+6]*16));
__m128i r7=_mm_loadu_si128((const __m128i *)(cached_signature+(size_t)od[j+7]*16));
__m128i t0=_mm_unpacklo_epi8(r0,r1);
__m128i t1=_mm_unpacklo_epi8(r2,r3);
__m128i t2=_mm_unpacklo_epi8(r4,r5);
__m128i t3=_mm_unpacklo_epi8(r6,r7);
__m128i u0=_mm_unpacklo_epi16(t0,t1);
__m128i u1=_mm_unpackhi_epi16(t0,t1);
__m128i u2=_mm_unpacklo_epi16(t2,t3);
__m128i u3=_mm_unpackhi_epi16(t2,t3);
__m128i v0=_mm_unpacklo_epi32(u0,u2);
__m128i v1=_mm_unpackhi_epi32(u0,u2);
__m128i v2=_mm_unpacklo_epi32(u1,u3);
__m128i v3=_mm_unpackhi_epi32(u1,u3);
__m128i h0=_mm_unpackhi_epi8(r0,r1);
__m128i h1=_mm_unpackhi_epi8(r2,r3);
__m128i h2=_mm_unpackhi_epi8(r4,r5);
__m128i h3=_mm_unpackhi_epi8(r6,r7);
__m128i hu0=_mm_unpacklo_epi16(h0,h1),hu1=_mm_unpacklo_epi16(h2,h3);
__m128i v4=_mm_unpacklo_epi32(hu0,hu1);
_mm_storel_epi64((__m128i *)(base+(size_t)0*MF_SPL+j),v0);
_mm_storel_epi64((__m128i *)(base+(size_t)1*MF_SPL+j),_mm_srli_si128(v0,8));
_mm_storel_epi64((__m128i *)(base+(size_t)2*MF_SPL+j),v1);
_mm_storel_epi64((__m128i *)(base+(size_t)3*MF_SPL+j),_mm_srli_si128(v1,8));
_mm_storel_epi64((__m128i *)(base+(size_t)4*MF_SPL+j),v2);
_mm_storel_epi64((__m128i *)(base+(size_t)5*MF_SPL+j),_mm_srli_si128(v2,8));
_mm_storel_epi64((__m128i *)(base+(size_t)6*MF_SPL+j),v3);
_mm_storel_epi64((__m128i *)(base+(size_t)7*MF_SPL+j),_mm_srli_si128(v3,8));
_mm_storel_epi64((__m128i *)(base+(size_t)8*MF_SPL+j),v4);
_mm_storel_epi64((__m128i *)(base+(size_t)9*MF_SPL+j),_mm_srli_si128(v4,8));
}
for(;j<N;j++) {
const u8 *row=cached_signature+(size_t)od[j]*16;
for(int e=0;e<k;e++)base[(size_t)e*MF_SPL+j]=row[e];
}
}
g_sig_merged=1;
}
if (s_sig && !g_sig_merged) {
for (int d = 0; d < k; d++) {
const u32 *od = s_ord[d];
u8 *base = s_sig + (size_t)d * k * MF_SPL;
for (u32 j = 0; j < N; j++) {
#if MF_PFB > 0
if (j + MF_PFB < N) _mm_prefetch((const char *)(s_pm + (size_t)od[j + MF_PFB] * STRIDE), _MM_HINT_T0);
#endif
const u32 *row = s_pm + (size_t)od[j] * STRIDE;
for (int e = 0; e < k; e++) { u32 v=sigfull(row[e]); base[(size_t)e * MF_SPL + j]=(u8)(v?v:1u); }
}
}
}
u64 poolwords = (u64)K1 * (Q + 1) * W;
#if MF_PLEN
if (g_plen_on) {
u64 best = 0;
for (int dsx = 0; dsx < k; dsx++) {
u64 tot = 0;
for (int e = 0; e < K1; e++) {
int d = (e < dsx) ? e : e + 1;
const u32 *mr = s_maxr + ((size_t)dsx * MAXK + d) * g_MS;
for (u32 b = 0; b <= Q; b++) {
u32 RR = mr[b];
u32 len = ((RR >> 6) + 8u) & ~7u;
if (len > W) len = W;
tot += len;
}
}
if (tot > best) best = tot;
}
if (best && best < poolwords) poolwords = best;
}
#endif
size_t need = (size_t)poolwords * sizeof(u64);
static u64 *pool = 0; static size_t cap2 = 0;
if (need > cap2) { pool = (u64 *)pool_alloc(need + 4096); cap2 = need; }
s_bs = pool;
for (int ds = 0; ds < k; ds++) {
u32 q0 = gstart[ds], q1 = gstart[ds + 1];
if (q0 >= q1) continue;
#if MF_WTRIM
{
u32 mx = 1;
if (g_plen_on) {
const int md = ds == 0 ? 1 : 0;
const u32 *mr = s_maxr + ((size_t)ds * MAXK + md) * g_MS;
for (u32 b = 0; b <= Q; ++b) if (mr[b] > mx) mx = mr[b];
} else {
for (u32 qi = q0; qi < q1; qi++) { u32 rr = s_gt[ds][s_qord[qi]&0xfffffu]; if (rr > mx) mx = rr; }
}
u32 wp = ((mx >> 6) + 8u) & ~7u;
g_nidwide = (mx > 65534u);
if (g_nidwide) wp = 1024u;
Wpool = (wp < W) ? wp : W;
g_nid16 = 1; g_nidmx = mx;
}
#endif
#if MF_PLEN
if (g_plen_on) {
u64 tot = 0;
for (int e = 0; e < K1; e++) {
int d = (e < ds) ? e : e + 1;
const u32 *mr = s_maxr + ((size_t)ds * MAXK + d) * g_MS;
u32 *po = s_pofs + (size_t)e * MAXQ;
u32 *pl = s_plen + (size_t)e * MAXQ;
for (u32 b = 0; b <= Q; b++) {
u32 RR = mr[b];
u32 len = ((RR >> 6) + 8u) & ~7u;
if (len > Wpool) len = Wpool;
po[b] = (u32)tot; pl[b] = len; tot += len;
}
}
if (tot > (u64)K1 * (Q + 1) * W) { g_plen_on = 0; }
}
#endif
const u16 *const active_rank16 = retained_rank16[ds];
if (!g_nid16) {
const u32 *od = s_ord[ds];
{
u32 lim_ = (N > 24u) ? (N - 24u) : 0u;
for (u32 j = 0; j < lim_; j++) {
__asm__ __volatile__("prefetchw %0" :: "m"(*(const char *)(s_nid + od[j + 24])));
s_nid[od[j]] = j;
}
for (u32 j = lim_; j < N; j++) s_nid[od[j]] = j;
}
}
for (int e = 0; e < K1; e++) {
int d = (e < ds) ? e : e + 1;
const unsigned *xd = x[d];
const u32 *od = s_ord[d];
u64 *base = g_plen_on ? s_bs : (s_bs + (size_t)e * (Q + 1) * Wpool);
u64 *cur = s_acc;
for (u32 w = 0; w < Wpool; w++) cur[w] = 0;
if (g_plen_on) {
u64 *d0 = s_bs + s_pofs[(size_t)e * MAXQ];
u32 l0 = s_plen[(size_t)e * MAXQ];
for (u32 w = 0; w < l0; w++) d0[w] = 0;
}
u32 ptr_ = 0;
#if MF_BUILD_NOPOOL
while (ptr_ < N) ptr_++;
#else
for (u32 b = 1; b < Q; b++) {
u32 pend = FPOS(d, b);
if (g_nid16) {
{
unsigned long long p_ = ptr_, e_ = pend;
const u32 *od_ = od; const u16 *rk_ = active_rank16; u64 *cu_ = cur;
unsigned long long q0_,q1_,q2_,q3_,t_;
__asm__ __volatile__(
"cmpq %[e], %[p]\n\t"
"jae 3f\n\t"
"1:\n\t"
"leaq 4(%[p]), %[t]\n\t"
"cmpq %[e], %[t]\n\t"
"ja 2f\n\t"
"testq $15, %[p]\n\t"
"jnz 4f\n\t"
"prefetchnta 512(%[od],%[p],4)\n\t"
"4:\n\t"
"movl 0(%[od],%[p],4), %k[q0]\n\t"
"movl 4(%[od],%[p],4), %k[q1]\n\t"
"movl 8(%[od],%[p],4), %k[q2]\n\t"
"movl 12(%[od],%[p],4), %k[q3]\n\t"
"movzwq 0(%[rk],%[q0],2), %[q0]\n\t"
"movzwq 0(%[rk],%[q1],2), %[q1]\n\t"
"movzwq 0(%[rk],%[q2],2), %[q2]\n\t"
"movzwq 0(%[rk],%[q3],2), %[q3]\n\t"
"addq $4, %[p]\n\t"
"shlx %[q0], %[one], %[t]\n\t"
"shrq $6, %[q0]\n\t"
"orq %[t], 0(%[cu],%[q0],8)\n\t"
"shlx %[q1], %[one], %[t]\n\t"
"shrq $6, %[q1]\n\t"
"orq %[t], 0(%[cu],%[q1],8)\n\t"
"shlx %[q2], %[one], %[t]\n\t"
"shrq $6, %[q2]\n\t"
"orq %[t], 0(%[cu],%[q2],8)\n\t"
"shlx %[q3], %[one], %[t]\n\t"
"shrq $6, %[q3]\n\t"
"orq %[t], 0(%[cu],%[q3],8)\n\t"
"jmp 1b\n\t"
"2:\n\t"
"cmpq %[e], %[p]\n\t"
"jae 3f\n\t"
"movl 0(%[od],%[p],4), %k[q0]\n\t"
"movzwq 0(%[rk],%[q0],2), %[q0]\n\t"
"addq $1, %[p]\n\t"
"shlx %[q0], %[one], %[t]\n\t"
"shrq $6, %[q0]\n\t"
"orq %[t], 0(%[cu],%[q0],8)\n\t"
"jmp 2b\n\t"
"3:\n\t"
: [p]"+r"(p_), [q0]"=&r"(q0_), [q1]"=&r"(q1_), [q2]"=&r"(q2_), [q3]"=&r"(q3_), [t]"=&r"(t_)
: [od]"r"(od_), [rk]"r"(rk_), [cu]"r"(cu_), [e]"r"(e_), [one]"r"(1ULL)
: "cc", "memory");
ptr_ = (u32)p_;
}
} else {
{
u32 lim_ = (pend > 26u) ? (pend - 26u) : ptr_;
while (ptr_ < lim_) {
__asm__ __volatile__("prefetcht0 %0" :: "m"(*(const char *)(s_nid + od[ptr_ + 26])));
u32 q = s_nid[od[ptr_]]; cur[q >> 6] |= 1ull << (q & 63); ptr_++;
}
while (ptr_ < pend) { u32 q = s_nid[od[ptr_]]; cur[q >> 6] |= 1ull << (q & 63); ptr_++; }
}
}
u64 *dst = g_plen_on ? (base + s_pofs[(size_t)e * MAXQ + b])
: (base + (size_t)b * Wpool);
u32 wlen = g_plen_on ? s_plen[(size_t)e * MAXQ + b] : Wpool;
#if MF_NT
{
u32 w = 0;
for (; w + 4 <= wlen; w += 4)
_mm256_stream_si256((__m256i *)(dst + w), _mm256_load_si256((const __m256i *)(cur + w)));
for (; w < wlen; w++) dst[w] = cur[w];
}
#else
{ u32 w = 0;
for (; w + 4 <= wlen; w += 4) _mm256_storeu_si256((__m256i *)(dst + w), LDU256((const __m256i *)(cur + w)));
for (; w < wlen; w++) dst[w] = cur[w]; }
#endif
}
_mm_sfence();
#endif
}
switch (k) {
default: query_group<10>(N, out, ds, q0, q1, Q, Wpool); break;
}
}
dimension_major_fringe<10>(N,out,B);
for (u32 i=0;i<N;i++) out[i]=(u32)(s_gc[i].cnt&0xFFFFu);
}
__attribute__((aligned(1024))) void count_10d(int n, const unsigned *x[10], unsigned *out) { solve_mf((u32)n, (const unsigned **)x, out, 10); }
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 94.624 ms | 43 MB + 584 KB | Accepted | Score: 100 | 显示更多 |