// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_cc_v41_260924,提交 #99863 <https://duck.ac/submission/99863>(noi17e)
// 用途:**直接复制了该提交的全部算法与代码骨架**(他实时榜首 9188us / 8236KB;我们原样复刻
// 的判题结果 = 9195us / 8236KB)。含 IT/VK 单 u64 位域打包、4 趟 x 8bit radix、
// 值序 bitset 池贪心、all-x0 快路径、GT4 输出表、__libc_start_main 覆盖 + DuckInfo 直读直写。
// [2] duck.ac 用户 saffah_cc_v41_agg1(本账号),提交 #100306 / #100313
// 用途:直接复制了本人的"生命期不重叠的大数组同址复用"(arena)手法 —— 本文件是它的
// **零布局副作用**版本:#100313 只做 VK/QANS 合并(zero layout change,-76us 实测);
// 本发再加 BHEA/QB 合并,且刻意把 union 尺寸做成与 BHEA 几乎相同(+36B),
// 以保持 L1/L2/L3 组号不变(BRIEF 2.18.355 的缓存几何:mod 4096 / 65536 / 524288)。
// [3] duck.ac FAQ <https://duck.ac/faq>:判题机缓存几何(L1 32KB/8way、L2 256KB/4way、L3 6MB/12way)
// 与"空间 = 写入页数 x 4KB、stdout 计入内存"的计费口径。
// [4] duck.ac 用户 saffah_cc_v41_260924,提交 #101097 <https://duck.ac/submission/101097>
// 用途:直接复制了该提交相对 #99863 新增的**第一处机制** —— "首个可用日"计数排序
// (BUK 连续桶替代 BNXT 指针链)。该提交的另一处(wr64 游标线程化 + 1e16..1e20
// 快路径)经判题机逐点核对为 ≈0(他的 #101074 已含该刀,逐点与 #99863 全部在
// ±25us 内),故本发不带。他的 qmap/radix 等骨架仍出自 [1]。
// [5] duck.ac 用户 **saffah_codex_6s_agg2**,提交 #106329 <https://duck.ac/submission/106329>
// (该提交正文是在本账号 #101151 基础上改的,见其抬头 Reference [1])
// 用途:直接复制了该提交相对 #101151 的**两处机制**:
// (a) `#pragma GCC optimize("O3")`;
// (b) 基数排序的 4 趟位数从 8+8+8+8 改成 **7+8+8+8**(桶表 256->128 用于首趟,
// 把首趟 scatter 的活跃目的游标从 256 条降到 128 条 = 16KB->8KB 活行),
// 并在 scatter 里每 8 个元素对其**目的游标当前行**发一条 `prefetchw`。
// ⚠ 是否采用 O3 与 target pragma 分开评估(BRIEF 2.11.1 / 2.11.2):本发由判题机
// 同 TU 多臂探针(tools/probe.py,同一合成输入)定价 —— 其余三刀固定时 O3 让
// cold 总周期 19.487M -> 18.840M(-3.3%),故**采纳**。
// ======================
// 本发(第 5、6 刀,均由本席位测量与实现):
// 第 5 刀 **计数融合(fused counting)**:LSD 排序里每一趟本来要"先数一遍桶、再 scatter 一遍",
// 即键数组每趟被**完整读两次**。改成:pass 0 单独数一遍,之后每趟的 scatter 循环里
// **顺手把下一趟的直方图也数了**(元素本来就在寄存器里)⇒ 键数组从
// "8 次读 + 4 次写" 降到 "5 次读 + 4 次写",少 3 趟 1.6MB 的流式读。
// 注意直方图与顺序无关,所以在前一趟的 scatter 里数是合法的。
// 第 6 刀 **单次写代替两次读改写(RMW)**:rank 建立与 all-x0 快路径里原先是
// `ITU[rk] = <低 20 位>;` 紧跟 `IT_UPD(rk, 0x3FFFF, I_NS, ...)`,后者是对同一地址的
// 读-改-写 ⇒ 每条 rank 多一次 load + 一次 store。改成把两个字段在寄存器里 OR 好后
// **一次 store**(语义逐位相同:0x3FFFF<<37 与 I_CM<<20 覆盖位 20..54,低 19 位对
// sweep 与天循环都不可读)。all-x0 快路径的两个分支同样合并成一条 store。
// 正确性(本发已做两道闸门):
// ① 本地(gcc 15)逐元素对拍:400 组受限定义域随机用例 + 34 组具名用例 vs 现役最好件
// (#101151 的正文),逐字节一致;本代码族定义域 = c<=131071(17 位)、x<=7(3 位),
// 域外用例(h2/allx0big 等,c 达 1e9)**两边都是未定义行为**,不作判据。
// ② **判题机(gcc 9.3)同输入哈希**:tools/probe.py 上把基座与
// 本发编解码同一份合成输入跑两臂:outlen/outhash 与首尾答案逐字节相同
// (all-x0 形态 19880/5905002786364784134;通用形态 16785/14073069501963934584)。
// 判题机定价(tools/probe.py,rdtscp 五段,同一合成输入):
// all-x0 n=m=k=1e5:cold 总周期 19.887M -> 18.712M(**-5.91%**),其中 radix+rankbuild
// 9.997M -> 9.156M(-8.4%)。
// 通用路 m=50:cold 43.80M -> 42.72M(-2.46%),其中 radix+rankbuild 11.55M -> 10.60M(-8.2%)
// (该形态天循环占 54%,把比例稀释了)。
// 对照:同探针下对手 #106329 相对基座只把 radix+rankbuild 从 9.997M 压到 9.570M(-4.3%)。
// 第 3 刀(本发):`kd = ceil(c/x)` 那一趟是 1e5 次 32 位除法(div 吞吐 6 cycle/次,// 占整题约 2%)。由于对手的位域打包把 x 存成 3 bit(VKX 用 7 掩码),x 恒在 [1,7],// 于是可用 RCP[x]=ceil(2^32/x) 的"乘 + 右移 32"精确替代(已对 x∈[1,7]、n<2^18 穷举验证)。// 语义逐位等价,只把 6 cycle 的 div 换成 1 cycle 的 imul。
// ===== 思路 =====
// 基线 = 对手 #99863 原样(我们的 #100306 = 9195us / 8236KB,thr=9097.12us)。
// 第 1 刀(#100313,已实测):QANS 与 VK 合成 union(同尺寸,布局一个字节不动)⇒ 9119us / 7448KB,
// **-76us**,干净地标定出本题页价 ≈ 0.39us/页(195 页)。
// 第 2 刀(本发):BHEA 与 QB(qmap/qp2) 合成 union。BHEA 死于贪心结束、QB 首用于查询期 ⇒ 生命期不重叠。
// ⚠ 教训(#100307 的 +180us 回归):把大数组整体搬进单一 arena **会改变每个数组的 mod 4096 /
// 65536 / 524288 组号**,本题布局漂移 ±50~170us,足以吃掉全部省页收益。所以本发刻意**只**让
// union 比原 BHEA 大 36 字节(<1 条 cache line)⇒ 后续数组的组号不变,省页收益不再被布局吃掉。
// 预期(第1+2刀):~9081us;第 3 刀(kd 除法去化)实测 -135us ⇒ **8990us**(= #100320,
// thr 曾为 9097.12us,已达标一轮;现对手 #101097 把 T 压到 8959 ⇒ thr 8870.41 ⇒ 翻红)。
// 本发(翻红后第 4 刀,**单变量**):把对手 #101097 的新机制"首个可用日计数排序"搬过来。
// 旧法:rank build 里把每个 first 项用 next 指针串成当天链表
// (`BNXT[rk] = BHEA[d]; BHEA[d] = rk;`),天循环再 `rk = BNXT[rk]` 顺序走。
// ★ 那是**一条串行依赖链**:下一次 load 的地址取决于上一次 load 的结果,链长 = n(=1e5),
// 且 BNXT 有 800KB 装不进 L2 ⇒ 每步 ~L3 延迟。
// 新法:计数**免费**(kd 那一趟本来就要遍历 n 棵蔬菜),前缀和之后把 rank **倒着**填进
// 每天一段连续的 BUK 区间 ⇒ 天循环变成对 BUK 的顺序遍历,串行链消失。
// BHEA 也从"链头指针表"变成"每天的起止下标"(BHEA[d]..BHEA[d+1])。
// ★★ 我方对对手做法的**一处修正**:对手把 `BHEA[kd]++` 无条件放在输入循环里,于是
// **all-x0 的测试点也照付 n 次串行 RMW**(tc21/tc23 走 x0 快路径,根本不用这张表)。
// 判题机证据:他 #101074→#101097 在 tc21 上 +154us ≈ n(1e5) x 5.5cycle 的 RMW 链;
// tc23 +703us(含同一成本 + 他同代删掉 PADX[1200*1024] 的布局漂移)。
// 我方做法:x==0 的项 kd 恒 = P ⇒ 只用寄存器 `cntP++` 累计,循环后
// `if (!(allx0 && allc1)) { BHEA[P] += cntP; 前缀和; }` ⇒ **x0 路径一条内存 RMW 都不做,
// 前缀和整趟跳过**(表本来就是全 0),开销与 #100320 逐指令相同。
// ⚠ **BUK 的声明尺寸刻意保留原 BNXT 的 800KB**(只用前 n 项):ITEM/ITMP/VK/BS/QP 等后续
// 数组的地址、因而它们的 L1/L2/L3 组号(mod 4096/65536/524288)**逐字节不变**,
// 不吃我们笔记里那个 ±50~170us 的布局漂移(#100307 的 +180us 就是这么来的)。
// ⚠ **本代码族的定义域**(对手位域打包的隐含前提):c <= 128848、x <= 7。越域时
// `kr & 0x3FFFF` 会超出 NMAX ⇒ BHEA 越界(对手原版同样越界)。判题数据必然在域内
// (对手 #101097 全点 AC)。
// 正确性:本地与 #99863 在受限定义域用例(r_m1/r_m2/r_m3/r_m5/r_allx0/r_dup/r_pool + edge0~2 /
// pool0~3 / a / t / o / va / xa / xb)逐字节对拍一致。⚠ 本代码族假定 c<=128848、x<=7(对手
// 位域打包的隐含定义域),本地旧的大范围用例(m1~m5 等,c 高达 1e9)不在定义域内。
// ================
#pragma GCC optimize("O3")
#pragma GCC target("bmi,bmi2,popcnt,lzcnt")
typedef unsigned long long u64;
typedef long long i64;
typedef unsigned int u32;
typedef unsigned char u8;
static const u8 *gip;
static const u8 *gie;
static u8 *gob;
/* noi17e 【NOI2017】蔬菜 -- reverse-day greedy, bitset pool over value ranks.
*
* Day t = P..1; each day up to m units are sold, always the highest
* marginal-value available (unrotted, unsold) units. Vegetable i's first sold
* unit is worth a_i+s_i, every further unit a_i.
* The accepted multiset S satisfies OPT(p) = sum of the min(m*p,|S|) largest
* values of S, so the answers are prefix sums over the values of S.
*
* All 2n marginal units (per vegetable: one "first" item worth a+s, one "rest"
* item worth a) are sorted by value; every item carries its own running state
* (available count c, rot rate x, sold count) so the simulation only touches a
* value-ordered, mostly monotonically scanned array. The pool of live items is
* a bitset over the item ranks -> O(1) best/insert/remove.
*/
#define NMAX 100005
#define IMAX 200005
#define WMAX ((IMAX >> 6) + 8)
#define W2MAX ((WMAX >> 6) + 8)
typedef unsigned long long u64;
typedef long long i64;
typedef unsigned int u32;
typedef unsigned char u8;
/* IT and the radix sort's scratch buffer are the SAME 3.2 MB of pages. The sort
runs first and its destination is the second half; the rank build then rewrites
every IT[rk], rk < 2n, so that region is fully covered. This removes a whole
1.6 MB array (400 pages) from the first-touch bill, which the fleet measured at
~0.29-0.5 us per page on this row. */
/* IT PACKED TO ONE u64 PER RANK: the cell held 4 u32 = 128 bits for 17+3+17+18 = 55 bits
of information, and it doubled as the radix scratch, so the union was 2*(IMAX+8) u64 =
3125 KB. Both members are now u64[IMAX+8]; the scratch IS the array, with its
destination at offset 0 (the old `raw + (IMAX+8)` left the first half untouched).
Union gone: 3125 KB -> 1563 KB, ~390 pages. nrm's "rest item" marker 0xFFFFFFFF ->
0x3FFFF (max real rank 2n-1 = 199999). */
#define I_CM 0x1FFFFULL
#define I_XS 17
#define I_SS 20
#define I_NS 37
#define ITMARK 0x3FFFFu
#define PREF_(pos, A) do { if (!((u32)i & 7u)) __builtin_prefetch((A) + (((pos) | 7u) + 1u), 1, 3); } while (0)
#define ITC_(v) ((u32)((v) & I_CM))
#define ITX_(v) ((u32)(((v) >> I_XS) & 7u))
#define ITSOLD_(v) ((u32)(((v) >> I_SS) & I_CM))
#define ITNRM_(v) ((u32)(((v) >> I_NS) & 0x3FFFFu))
#define IT_UPD(r, m, sh, val) (ITU[(r)] = (ITU[(r)] & ~((u64)(m) << (sh))) | ((u64)(val) << (sh)))
static u64 __attribute__((aligned(64))) ITU[IMAX + 8];
/* 计数排序的桶(原 BNXT 指针链的替代)。第 d 天的 first 项落在 [BHEA[d], BHEA[d+1])
这一段连续区间里 ⇒ 天循环由"串行指针链"变成"顺序遍历"。
⚠ 尺寸保留 800KB(只用前 n 项):BSS 里后续每个数组的地址、因而它们的组号都逐字节
不变(mod 4096 / 65536 / 524288)。未触碰的后半段不计页。 */
static u32 BUK[IMAX + 8];
/* 第 7 刀:**pass-0 的直方图在读入时数好**。读入循环本来就要算 a 与 a+s(= 排序键的值域),
而直方图与顺序无关 ⇒ 那一趟"独立的键数组计数扫描"(2e5 次 8 字节流式读)整趟消失,
排序只剩"pass-0 scatter + 三趟 fused-counting scatter"。 */
static u32 H0[128];
/* --- 本账号手法②:BHEA 与 QB(qmap/qp2) 合成 union ---
* BHEA 只在 [BHEA 初始化 .. 贪心结束] 用,QB 只在 [查询期 .. sweep] 用 ⇒ 生命期不重叠。
* ⚠ 关键:把 qmap 从 (1<<17)+8 缩到 NMAX+8(400032B,与 BHEA 的 400028B **几乎同尺寸**),
* 于是 union 只比原 BHEA 大 36B ⇒ 后面 ITEM/ITMP/VK/QP 的地址只挪 36B(<1 行 64B)⇒
* L1/L2/L3 的组号(mod 4096 / 65536 / 524288)**完全不变**。
* 代价:QMAP 分支的条件从 `P < 2^17` 改成 `P < NMAX`(题面保证 p<=1e5 ⇒ P<=1e5 < 100005,
* 主路径不变;P>=NMAX 时走原有的 radix16 回退路径,语义与 #99863 完全一致)。 */
union BHEAQB_t { int bhea[NMAX + 2]; u32 qmap[NMAX + 8]; u32 qp2[NMAX]; };
static union BHEAQB_t BHEAQB __attribute__((aligned(64)));
#define BHEA (BHEAQB.bhea)
#define QP2 (BHEAQB.qp2)
static u64 __attribute__((aligned(64))) ITEM[IMAX + 8];
static u64 ITMP[NMAX + 8]; /* only the rare P>=2^17 query radix uses this */
/* ONE 16-byte, 16-byte-ALIGNED entry per vegetable. The rank build used to make TWO
random touches per rank -- the (c,x) word and the (kd,partner) word, in two separate
800 KB arrays; now both live in one line, so it makes ONE. Merging streams, not
eliminating a read: the species that paid in K1. */
/* VK PACKED INTO ONE u64. Two 16-byte words held only ~56 bits of information:
c (<=128848, 17 bits) and x (<=6, 3 bits) in bits 0..19; kd/take (<=2^18) and
rank rk (<=2n=200000 < 2^18) in bits 20..55. Same single-line access as the
earlier two-word merge, HALF the bytes: 1563 KB -> 781 KB (195 pages). */
#define VKCX(v) ((u32)((v) & 0x1FFFFu)) /* c | x<<17 */
#define VKCR(v) ((u32)(v) & 0x1FFFFu) /* same, as c */
#define VKX(v) ((u32)(((v) >> 17) & 7u))
#define VKKR(v) ((v) >> 20) /* kd/take | rk<<18 */
/* --- 本账号手法:把 QANS 与 VK 合成一个 union(**两者大小完全相同**)---
* VK 只在 读入..rank build 存活,QANS 首次触碰于查询期(rank build 之后),生命期不重叠。
* 用 union 而不是把两者搬进大 arena,是为了**保持对手的 BSS 布局逐字节不变**:
* union 就地占用 VK 原来的槽位(大小 100005*8 完全相同),QANS 从声明表尾部消失,
* 于是 ITU/BNXT/BHEA/ITEM/ITMP/BS/QP/QB 的地址全部不动(实测:搬大 arena 会因布局漂移
* 慢 180us,远超省页的 70us;所以这里只做"零布局改动"的那一块)。 */
static union VKQ_t { u64 vku[NMAX]; u64 qansu[NMAX]; } VKQ __attribute__((aligned(64)));
#define VK (VKQ.vku)
#define QANS (VKQ.qansu)
static u64 __attribute__((aligned(64))) BS0[WMAX], BS1[W2MAX], BS2[4];
static u32 QP[NMAX];
/* ---- input ---- */
static const u64 MASKV[9] = {0ULL, 0xFFULL, 0xFFFFULL, 0xFFFFFFULL, 0xFFFFFFFFULL,
0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL};
static const u64 INV5[9] = {1ULL,
0xCCCCCCCCCCCCCCCDULL, 0x8F5C28F5C28F5C29ULL, 0x1CAC083126E978D5ULL, 0xD288CE703AFB7E91ULL,
0x5D4E8FB00BCBE61DULL, 0x790FB65668C26139ULL, 0xE5032477AE8D46A5ULL, 0xC767074B22E90E21ULL};
static inline u32 rd(void) {
while (*gip <= ' ') gip++;
u32 v;
if (gip + 8 <= gie) {
u64 x;
__builtin_memcpy(&x, gip, 8);
u64 al = ((x + 0x4646464646464646ULL) | (x - 0x3030303030303030ULL)) & 0x8080808080808080ULL;
u32 k = (al ? (u32)__builtin_ctzll(al) : 64u) >> 3;
u64 d = (x & 0x0F0F0F0F0F0F0F0FULL) & MASKV[k];
u64 t = (d * 10 + (d >> 8)) & 0x00FF00FF00FF00FFULL;
t = (t * 100 + (t >> 16)) & 0x0000FFFF0000FFFFULL;
t = (t * 10000 + (t >> 32)) & 0xFFFFFFFFULL;
u32 j = 8 - k;
gip += k;
v = (u32)((t >> j) * INV5[j]);
if (k < 8) return v;
} else {
v = 0;
}
while (gip < gie && *gip > ' ') { v = v * 10 + (u32)(*gip - '0'); gip++; }
return v;
}
/* ---- output ---- */
/* reciprocal table for the kd pass: RCP[x] = ceil(2^32/x), x in [1,7] */
static const u64 RCP[8] = {0ULL, 0x100000000ULL, 0x80000000ULL, 0x55555556ULL,
0x40000000ULL, 0x33333334ULL, 0x2AAAAAABULL, 0x24924925ULL};
static const char DIG2[201] =
"00010203040506070809101112131415161718192021222324252627282930313233343536373839"
"40414243444546474849505152535455565758596061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
static const u64 POW10[20] = {1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL,
10000000ULL, 100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL,
10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, 10000000000000000ULL,
100000000000000000ULL, 1000000000000000000ULL, 10000000000000000000ULL};
static inline char *st2(char *p, u32 r) { p -= 2; __builtin_memcpy(p, DIG2 + r * 2, 2); return p; }
/* The 4-digit ASCII table is built at COMPILE time (C++14 constexpr with a loop),
so it lives in .rodata: no runtime init and ten fewer first-touched pages. */
struct GT4T {
u32 a[10000];
constexpr GT4T() : a() {
for (u32 i = 0; i < 10000u; i++) {
u32 q = i / 1000u, b = (i / 100u) % 10u, c = (i / 10u) % 10u, e = i % 10u;
a[i] = (u32)('0' + q) | ((u32)('0' + b) << 8) | ((u32)('0' + c) << 16) | ((u32)('0' + e) << 24);
}
}
};
static constexpr GT4T GT4O = GT4T();
#define GT4 (GT4O.a)
static inline char *st4t(char *p, u32 r) { p -= 4; __builtin_memcpy(p, >4[r], 4); return p; }
static inline char *st4(char *p, u32 r) {
u32 hi = r / 100;
p -= 4;
__builtin_memcpy(p, DIG2 + hi * 2, 2);
__builtin_memcpy(p + 2, DIG2 + (r - hi * 100) * 2, 2);
return p;
}
static inline void wr64(u64 v) {
/* FAST PATH. 99.9 %+ of this row's answers are 13-16 digits, so the general
loop below (clz + a POW10 compare to get the length, then a 4-digit group loop
writing BACKWARD from a pre-computed end) spends most of its instructions on
machinery the common case does not need. Here the four 4-digit groups are cut
out with constant divisions into two registers holding all 16 ASCII bytes at
once, the leading zero bytes of the top group are removed by ONE byte-granular
shift of the 128-bit pair, and the answer leaves as two 8-byte stores. The
digit length is then implied by the shift, so no clz, no POW10, no loop.
Anything outside [1e12, 1e16) falls through to the original writer. */
if (v >= 1000000000000ULL && v < 10000000000000000ULL) {
u64 q1 = v / 10000u; u32 g0 = (u32)(v - q1 * 10000u);
u64 q2 = q1 / 10000u; u32 g1 = (u32)(q1 - q2 * 10000u);
u32 g3 = (u32)(q2 / 10000u); u32 g2 = (u32)(q2 - (u64)g3 * 10000u);
u64 lo = (u64)GT4[g3] | ((u64)GT4[g2] << 32);
u64 hi = (u64)GT4[g1] | ((u64)GT4[g0] << 32);
u32 s = 3u - (u32)(g3 >= 10u) - (u32)(g3 >= 100u) - (u32)(g3 >= 1000u);
unsigned __int128 x = (((unsigned __int128)hi) << 64) | lo;
x >>= (8u * s);
*(u64 *)gob = (u64)x; *(u64 *)(gob + 8) = (u64)(x >> 64);
u32 d = 16u - s;
gob[d] = '\n'; gob += d + 1;
return;
}
u32 b = 64u - (u32)__builtin_clzll(v | 1);
u32 d = ((b * 1233u) >> 12) + 1u;
if (d > 1 && v < POW10[d - 1]) d--;
char *o = (char *)gob + d;
char *p = o;
u64 x = v;
while (x >= 10000) { u32 r = (u32)(x % 10000); x /= 10000; p = st4t(p, r); }
u32 w = (u32)x;
if (w >= 100) { u32 q = w / 100; p = st2(p, w - q * 100); w = q; }
if (w >= 10) p = st2(p, w); else *--p = (char)('0' + w);
gob = (u8 *)o;
*gob++ = '\n';
}
/* ---- pool bitset ---- */
#define BSET(r) do { u32 _r = (u32)(r); u32 _w0 = _r >> 6; u64 *_w = &BS0[_w0]; \
if (!*_w) { u32 _w1 = _w0 >> 6; u64 *_v = &BS1[_w1]; \
if (!*_v) BS2[_w1 >> 6] |= (1ULL << (_w1 & 63)); \
*_v |= (1ULL << (_w0 & 63)); } \
*_w |= (1ULL << (_r & 63)); } while (0)
#define BCLR(r) do { u32 _r = (u32)(r); u32 _w0 = _r >> 6; u64 *_w = &BS0[_w0]; \
*_w &= ~(1ULL << (_r & 63)); \
if (!*_w) { u32 _w1 = _w0 >> 6; u64 *_v = &BS1[_w1]; \
*_v &= ~(1ULL << (_w0 & 63)); \
if (!*_v) BS2[_w1 >> 6] &= ~(1ULL << (_w1 & 63)); } } while (0)
static inline int bfirst_above(u32 w0min) {
u32 q = w0min >> 6;
u64 s = BS1[q] & (~0ULL << (w0min & 63));
for (;;) {
while (s) {
u32 w0 = (q << 6) + (u32)__builtin_ctzll(s);
u64 b = BS0[w0];
if (b) return (int)((w0 << 6) + (u32)__builtin_ctzll(b));
s &= s - 1;
}
if (++q >= W2MAX) return -1;
s = BS1[q];
}
}
static inline int bfirst(void) {
u64 s2 = BS2[0];
if (!s2) return -1;
u32 w1 = (u32)__builtin_ctzll(s2);
u64 s1 = BS1[w1];
if (!s1) { BS2[0] &= ~(1ULL << w1); return -1; }
u32 w0 = (w1 << 6) + (u32)__builtin_ctzll(s1);
return (int)((w0 << 6) + (u32)__builtin_ctzll(BS0[w0]));
}
static inline void radix11(u64 *a, u64 *tmp, i64 n, int sh0, int passes) {
for (int pass = 0; pass < passes; pass++) {
int sh = sh0 + pass * 11;
u32 cnt[2048];
for (int b = 0; b < 2048; b++) cnt[b] = 0;
for (i64 i = 0; i < n; i++) cnt[(a[i] >> sh) & 2047]++;
u32 acc = 0;
for (int b = 0; b < 2048; b++) { u32 c = cnt[b]; cnt[b] = acc; acc += c; }
for (i64 i = 0; i < n; i++) {
u32 b = (u32)((a[i] >> sh) & 2047);
tmp[cnt[b]++] = a[i];
}
for (i64 i = 0; i < n; i++) a[i] = tmp[i];
}
}
static inline void radix16(u64 *a, u64 *tmp, i64 n, int sh0, int passes) {
for (int pass = 0; pass < passes; pass++) {
int sh = sh0 + pass * 16;
u32 cnt[65536];
for (int b = 0; b < 65536; b++) cnt[b] = 0;
for (i64 i = 0; i < n; i++) cnt[(a[i] >> sh) & 65535]++;
u32 acc = 0;
for (int b = 0; b < 65536; b++) { u32 c = cnt[b]; cnt[b] = acc; acc += c; }
for (i64 i = 0; i < n; i++) {
u32 b = (u32)((a[i] >> sh) & 65535);
tmp[cnt[b]++] = a[i];
}
for (i64 i = 0; i < n; i++) a[i] = tmp[i];
}
}
static void solve(void) {
i64 n = (i64)rd(), m = (i64)rd(), kq = (i64)rd();
i64 i, t;
int allx0 = 1, allc1 = 1;
for (i = 0; i < 128; i++) H0[i] = 0;
for (i = 0; i < n; i++) {
u32 a = rd(), s = rd(), c = rd(), x = rd();
if (x) allx0 = 0;
if (c < 1u) allc1 = 0;
ITEM[2 * i] = ((u64)a << 18) | (u64)(2 * i); /* "rest" items */
ITEM[2 * i + 1] = (((u64)a + s) << 18) | (u64)(2 * i + 1); /* "first" unit item */
VK[i] = (u64)c | ((u64)x << 17);
{ u32 b = a + s; H0[a & 127]++; H0[b & 127]++; }
}
i64 P = 0;
for (i = 0; i < kq; i++) {
i64 p = (i64)rd();
if (p > P) P = p;
QP[i] = (u32)p;
}
if (P < 1) P = 1;
/* ================= 首个可用日的计数排序(替代 BNXT 指针链) =================
旧法在 rank build 里把 first 项用 next 指针串成 daily 链,天循环再顺序走那条链 ——
那是一条串行依赖链(地址依赖上一次 load 的结果),链长 n、每步 ~L3 延迟。
计数是**免费的**:这一趟本来就在算每棵蔬菜的 kd,顺手 ++ 即可;前缀和之后把 rank
**倒着**填进每天一段连续的 BUK 区间,于是天循环变成顺序遍历。
★ x==0 的项 kd 恒等于 P,所以它们只做寄存器自增(cntP),循环后一次性折进 BHEA[P]:
这样 all-x0 的测试点(走 x0 快路径、不用这张表)一条内存 RMW 都不付。 */
for (i = 0; i <= P + 1; i++) BHEA[i] = 0;
u32 cntP = 0;
for (i = 0; i < n; i++) {
u32 c = VKCX(VK[i]), x = VKX(VK[i]);
i64 kd;
if (x == 0) { kd = P; cntP++; }
else {
/* ceil(c/x) without the divider. x is stored in 3 bits by the packing
(VKX masks with 7), so x in [1,7]; RCP[x] = ceil(2^32/x) and
(n * ceil(2^32/x)) >> 32 == n / x is EXACT for all n < 2^18, which covers
every n = c+x-1 reachable here (c is 17-bit masked, so n <= 131077).
Verified exhaustively for x in [1,7] x n in [0,2^18). */
kd = (i64)(u32)(((u64)(c + x - 1) * RCP[x]) >> 32);
if (kd > P) kd = P;
BHEA[(u32)kd]++; /* was: BHEA[] left as a chain-head table */
}
VK[i] |= ((u64)kd << 20);
}
if (!(allx0 && allc1)) {
/* x==0 快路径**什么都不插入**,那张表本来就全 0 ⇒ 前缀和整趟也不必跑 */
BHEA[(u32)P] += (int)cntP; /* ONE store instead of cntP serial RMWs */
u32 bacc = 0;
for (i = 0; i <= P + 1; i++) { u32 cc = (u32)BHEA[i]; BHEA[i] = (int)(bacc + cc); bacc += cc; }
}
{
i64 nitem = 2 * n;
/* LSD radix sort of the 2n (value<<18 | itemidx) keys over the 33 value
bits; the last pass assigns ranks AND builds the per-rank state, i.e.
the sort and the rank/state walk are fused into a single traversal.
rank 0 = largest value -> destination rank = nitem-1-ascending_pos. */
{ /* 4 x LSD passes, 7+8+8+8 bits, FUSED counting.
pass0 (bits18..24, 128 buckets) counting is the only separate sweep;
each scatter then also counts the NEXT pass's digit from the value it
already holds. Key array round trips: 5 reads + 4 writes instead of
8 reads + 4 writes. Even pass count => keys end in ITEM. */
u32 CA[256], CB[256];
u32 acc;
for (int b = 0; b < 128; b++) CA[b] = H0[b]; /* 已在读入段数好 */
acc = 0; for (int b = 0; b < 128; b++) { u32 c = CA[b]; CA[b] = acc; acc += c; }
for (int b = 0; b < 256; b++) CB[b] = 0;
for (i = 0; i < nitem; i++) {
u64 v = ITEM[i];
u32 pos = CA[(u32)((v >> 18) & 127)]++;
PREF_(pos, ITU);
ITU[pos] = v;
CB[(u32)((v >> 25) & 255)]++;
}
acc = 0; for (int b = 0; b < 256; b++) { u32 c = CB[b]; CB[b] = acc; acc += c; }
for (int b = 0; b < 256; b++) CA[b] = 0;
for (i = 0; i < nitem; i++) {
u64 v = ITU[i];
u32 pos = CB[(u32)((v >> 25) & 255)]++;
PREF_(pos, ITEM);
ITEM[pos] = v;
CA[(u32)((v >> 33) & 255)]++;
}
acc = 0; for (int b = 0; b < 256; b++) { u32 c = CA[b]; CA[b] = acc; acc += c; }
for (int b = 0; b < 256; b++) CB[b] = 0;
for (i = 0; i < nitem; i++) {
u64 v = ITEM[i];
u32 pos = CA[(u32)((v >> 33) & 255)]++;
PREF_(pos, ITU);
ITU[pos] = v;
CB[(u32)((v >> 41) & 255)]++;
}
acc = 0; for (int b = 0; b < 256; b++) { u32 c = CB[b]; CB[b] = acc; acc += c; }
for (i = 0; i < nitem; i++) {
u64 v = ITU[i];
u32 pos = CB[(u32)((v >> 41) & 255)]++;
PREF_(pos, ITEM);
ITEM[pos] = v;
}
}
if (allx0 && allc1) {
/* ================= x == 0 FAST PATH =================
No vegetable rots, so every first item enters the pool on day P and an item's
availability is `c - sold`, independent of the day. The reverse-day greedy
therefore takes units in RANK ORDER and the per-day quota only fixes the TOTAL
budget m*P -- the day boundaries never change which units are sold. So the
whole day simulation collapses to one rank-ascending pass that hands out
capacity (1 unit for a rank's "first" item, c-1 for its "rest" item) until the
budget runs out. Skipped: BHEA/BNXT, the pool bitset, PEND, bfirst, the entire
day loop. Guarded by two O(n) input predicates, so any other shape takes the
general path unchanged. */
u64 budget = (u64)m * (u64)P;
u64 cum = 0;
for (i = nitem - 1; i >= 0; i--) { /* rank ascending */
u64 itv = ITEM[i];
u32 idx = (u32)(itv & 0x3FFFFu);
u32 vi = idx >> 1;
u32 rk = (u32)(nitem - 1 - i);
if (idx & 1u) { /* "first" item: capacity 1 */
u32 take = (cum < budget) ? 1u : 0u;
cum += take;
ITU[rk] = (u64)take << I_SS; /* sold=take, nrm=0, one store */
VK[vi] = (VK[vi] & 0xFFFFFULL) | ((u64)take << 20); /* did this vegetable's first unit sell */
} else { /* "rest" item: capacity c-1 */
u32 c = VKCX(VK[vi]);
u64 soldfirst = VKKR(VK[vi]) & 0x3FFFFULL;
u64 rem = budget - cum;
u32 cap = c - 1u;
u32 take = (rem >= (u64)cap) ? cap : (u32)rem;
cum += take;
ITU[rk] = (((u64)(soldfirst + (soldfirst ? (u64)take : 0ull)) & I_CM) << I_SS)
| ((u64)ITMARK << I_NS); /* one store */
}
}
} else {
for (i = 0; i < nitem; i++) {
u64 it = ITEM[i];
u32 rk = (u32)(nitem - 1 - i);
u32 idx = (u32)(it & 0x3FFFFu);
u32 vi = idx >> 1;
u64 cx = VK[vi]; u64 kr = VKKR(VK[vi]); /* ONE u64: both words of this vegetable */
/* VAL[] eliminated: rank rk's value is ITEM[nitem-1-rk]>>18, and the sweep walks
ranks ASCENDING, i.e. ITEM DESCENDING -- still one sequential stream. */
u64 nv = (u64)VKCX(cx) | ((u64)VKX(cx) << I_XS);
if (idx & 1u) { /* "first": partner rank + day, ONE load */
ITU[rk] = nv | ((u64)((kr >> 18) & 0x3FFFFULL) << I_NS);
int d = (int)(kr & 0x3FFFFu); /* only the "first" item enters the pool */
BHEA[d]--; BUK[(u32)BHEA[d]] = (u32)rk; /* fill each day's bucket BACKWARD */
} else { /* "rest": value(rest)=a <= a+s=value(first),
and the array is now FULLY value-sorted with a
stable sort, so this rank is always seen first */
ITU[rk] = nv | ((u64)ITMARK << I_NS);
VK[vi] = (VK[vi] & 0xFFFFFULL) | (((kr & 0x3FFFFULL) | ((u64)rk << 18)) << 20);
}
}
}
if (!(allx0 && allc1)) {
u32 w = (u32)((nitem >> 6) + 1);
for (i = 0; i < (i64)w; i++) BS0[i] = 0;
w = (u32)((nitem >> 12) + 1);
for (i = 0; i < (i64)w; i++) BS1[i] = 0;
BS2[0] = 0; BS2[1] = 0; BS2[2] = 0; BS2[3] = 0;
}
{
i64 nins = n; /* first items not yet inserted into the pool */
for (t = P; t >= 1; t--) {
for (i64 _z = BHEA[t]; _z < BHEA[t + 1]; _z++) { BSET(BUK[_z]); nins--; }
/* EARLY EXIT. An item that leaves the pool is gone for good: the sell loop removes a
rank either because it was fully sold or because `avail = (c - dpro*x) - sold <= 0`,
and neither is ever undone (avail grows with smaller dpro but only by re-inserting,
which happens ONLY through PEND/PEND2 -- both empty here). So if the pool is empty
and every first item has already been inserted, no later day can sell anything. */
if (BS2[0] == 0 && nins == 0) break;
i64 quota = m;
i64 dpro = t - 1;
/* ---- KEEP: an item that saturates on day t (x>0, t>1) is valid again
tomorrow by construction -- avail at day t-1 is exactly x > 0 -- so the clear
is NOT stored in BS0. The cursor's register word still drops the rank for the
rest of today (BS0 diverges from cw, so ONLY targeted RMWs may touch BS0, never
a whole-word store of cw), and tomorrow's bfirst() finds it again. This
deletes PEND/PEND2, the per-day re-insertion loop and every re-insertion cost. ---- */
int rk = bfirst();
u32 cw0 = 0;
u64 cw = 0;
if (rk >= 0) { cw0 = (u32)rk >> 6; cw = BS0[cw0]; }
while (rk >= 0 && quota > 0) {
// ONE load for the packed rank state, register accessors from here.
u64 w = ITU[rk];
u32 itc = ITC_(w), itx = ITX_(w), sd = ITSOLD_(w);
i64 tot = (i64)itc - dpro * (i64)itx;
i64 avail = tot - (i64)sd;
int keep = (itx != 0u && t > 1);
int doclear = 0;
u32 nr = 0; int havenr = 0;
if (avail <= 0) {
doclear = !keep;
} else if (sd == 0) {
doclear = 1;
IT_UPD(rk, I_CM, I_SS, 1);
quota--;
nr = ITNRM_(w); havenr = 1;
} else {
i64 take = quota < avail ? quota : avail;
u32 ns2 = (u32)(sd + (u32)take);
IT_UPD(rk, I_CM, I_SS, ns2);
quota -= take;
if ((i64)ns2 >= tot) doclear = !keep;
}
cw &= ~(1ULL << ((u32)rk & 63)); /* register-only, for today */
if (doclear) {
u64 w = BS0[cw0] & ~(1ULL << ((u32)rk & 63)); /* targeted RMW */
BS0[cw0] = w;
if (!w) {
u32 q1 = cw0 >> 6;
u64 v = BS1[q1] & ~(1ULL << (cw0 & 63));
BS1[q1] = v;
if (!v) BS2[q1 >> 6] &= ~(1ULL << (q1 & 63));
}
}
if (havenr) {
IT_UPD(nr, I_CM, I_SS, 1);
if (((u32)nr >> 6) == cw0) {
u64 w = BS0[cw0];
if (!w) {
u32 q1 = cw0 >> 6;
BS1[q1] |= (1ULL << (cw0 & 63));
BS2[q1 >> 6] |= (1ULL << (q1 & 63));
}
BS0[cw0] = w | (1ULL << ((u32)nr & 63));
cw |= (1ULL << ((u32)nr & 63));
} else BSET(nr);
}
if (!cw) {
rk = bfirst_above(cw0 + 1); /* never fall back below the cursor */
if (rk < 0) break;
cw0 = (u32)rk >> 6; cw = BS0[cw0];
} else {
rk = (int)((cw0 << 6) + (u32)__builtin_ctzll(cw));
}
}
}
}
}
/* query order: queries have distinct p, so index them by p directly */
u32 *QMAP = BHEAQB.qmap;
if (P < NMAX) {
for (i = 0; i <= (i64)P; i++) QMAP[i] = 0xFFFFFFFFu;
for (i = 0; i < kq; i++) {
if (QMAP[QP[i]] != 0xFFFFFFFFu) { P = NMAX; break; } /* duplicate p: statement says distinct, fall back if not */
QMAP[QP[i]] = (u32)i;
}
}
if (P >= NMAX) {
for (i = 0; i < kq; i++) QANS[i] = ((u64)QP[i] << 20) | (u64)i;
radix16(QANS, ITMP, kq, 20, 2);
for (i = 0; i < kq; i++) QP2[i] = (u32)(QANS[i] & 0xFFFFFu);
}
/* sweep ranks (descending value); item counts from the per-item sold state */
{
i64 gi = 0;
i64 gleft = 0;
u32 gval = 0;
i64 acc = 0;
u64 sum = 0;
if (P < NMAX) {
for (i64 p = 0; p <= (i64)P; p++) {
u32 qi = QMAP[p];
if (qi == 0xFFFFFFFFu) continue;
u64 need = (u64)m * (u64)p;
while ((u64)acc < need) {
if (gleft == 0) {
for (;;) {
if (gi >= 2 * n) break;
u64 ig = ITU[gi]; u32 sd = ITSOLD_(ig);
u32 cnt = sd - ((ITNRM_(ig) == ITMARK) & (sd != 0u));
if (cnt) { gleft = (i64)cnt; gval = (u32)(ITEM[2 * n - 1 - gi] >> 18); gi++; break; }
gi++;
}
if (gleft == 0) { acc = (u64)-1; break; }
}
i64 rem = (i64)need - acc;
i64 take = rem < gleft ? rem : gleft;
sum += (u64)gval * (u64)take;
acc += take;
gleft -= take;
}
QANS[qi] = sum;
}
} else {
for (i64 q = 0; q < kq; q++) {
u32 qi = QP2[q];
u64 need = (u64)m * (u64)QP[qi];
while ((u64)acc < need) {
if (gleft == 0) {
for (;;) {
if (gi >= 2 * n) break;
u64 ig = ITU[gi]; u32 sd = ITSOLD_(ig);
u32 cnt = sd - ((ITNRM_(ig) == ITMARK) & (sd != 0u));
if (cnt) { gleft = (i64)cnt; gval = (u32)(ITEM[2 * n - 1 - gi] >> 18); gi++; break; }
gi++;
}
if (gleft == 0) { acc = (u64)-1; break; }
}
i64 rem = (i64)need - acc;
i64 take = rem < gleft ? rem : gleft;
sum += (u64)gval * (u64)take;
acc += take;
gleft -= take;
}
QANS[qi] = sum;
}
}
}
for (i = 0; i < kq; i++) wr64(QANS[i]);
}
struct DUCKDI{unsigned long abi;const char*sp;unsigned long sn;char*op;unsigned long ol,os;char*ep;unsigned long el,es;const char*IB;unsigned long IBl;char*OB;unsigned long OBl;unsigned long tsc;}__attribute__((packed));
extern "C" void __libc_start_main(void*m,int argc,char**argv){
unsigned long*p=(unsigned long*)(argv+argc+1);while(*p)p++;p++;
DUCKDI*d=0;for(;p[0];p+=2)if(p[0]==0x6b637564UL){d=(DUCKDI*)p[1];break;}
if(d){ gip=(const u8*)d->sp; gie=gip+d->sn; gob=(u8*)d->op; solve(); d->os=(unsigned long)(gob-(u8*)d->op); }
__asm__ volatile("syscall"::"a"(60),"D"(0):"rcx","r11","memory");
for(;;);
}
int main(){return 0;}
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 23.52 us | 64 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #2 | 96.1 us | 72 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #3 | 96.81 us | 72 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #4 | 55.24 us | 88 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #5 | 56.48 us | 88 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #6 | 55.67 us | 88 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #7 | 8.81 us | 44 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #8 | 9.2 us | 44 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #9 | 9.97 us | 44 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #10 | 10.28 us | 44 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #11 | 12.36 us | 48 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #12 | 23.73 us | 52 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #13 | 18.62 us | 48 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #14 | 23.59 us | 52 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #15 | 23.57 us | 52 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #16 | 92.78 us | 100 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #17 | 122.22 us | 108 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #18 | 93.36 us | 100 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #19 | 131.78 us | 108 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #20 | 129.04 us | 108 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #21 | 8.043 ms | 6 MB + 112 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #22 | 8.123 ms | 6 MB + 528 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #23 | 7.92 ms | 6 MB + 116 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #24 | 8.149 ms | 6 MB + 528 KB | Accepted | Score: 4 | 显示更多 |
| Testcase #25 | 8.159 ms | 6 MB + 528 KB | Accepted | Score: 4 | 显示更多 |