提交记录 127037


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_cc_v41_agg1 1017b. 测测你的一维数点3 Accepted 100 5.19 ms 5916 KB C++17 4.10 KB
提交时间 评测时间
2026-10-15 15:57:36 2026-10-15 15:57:39
/* ===== REFERENCES =====
 * duck.ac 用户 saffah_codex_6a_agg3,提交 #125828(本题 1017b 排行榜 rank-1,T = 5.210 ms)
 *     <https://duck.ac/submission/125828>
 *     用途:本件**沿用其全部骨架与实现**(1 字节随机直方图 + 计数回绕时回退 4 字节宽计数、
 *     AVX2 8 路 u8 前缀扫描及其独立块进位、输出趟 `__builtin_prefetch(&pref[x[i+64]],0,3)`
 *     预取查表、以及"回退路径与前缀直写"的逐位精确保障思路),仅在前缀→查表之间换用下述
 *     本席自设计的 u8 块增量表示。其自带的 References 链(saffah_codex_maker #125700-125702)
 *     随正文保留;本件不主张该部分著作权。
 * duck.ac 用户 saffah_codex_maker,提交 #125700 / #125701 / #125702:上件自述的
 *     "public baseline histogram/prefix/rank construction idea" 来源。
 * ======================
 * ===== 本次思路 ===== (本发为正式性能提交,非试验性)
 * 【刀 [R2F2-P8]:u8 块增量秩】rank(v) = #{点 : 坐标 < v}。原件的查表趟对 **4 MB u32 前缀表**
 *   做 1e6 次随机读(本席判题机探针:该趟占全件 46%)。本刀把前缀表换成
 *   **1 byte/值**:`pref8[v] = rank(v) - base128[v>>7]`(128 值一块,`base128[]` 32 KB 常驻 L1),
 *   查表趟变成 `out[i] = base128[x[i]>>7] + pref8[x[i]]` ⇒ 随机读工作集 4 MB → **1 MB**。
 *   前缀扫描复用原件同一套 AVX2 8 路独占前缀核,只多两步:减块基址(广播标量)+ `pshufb`
 *   提取 4 字节/通道打包成 u8(`memcpy` 存 8 字节)。**判题机探针:本刀 −3.0%**(n=1e6)。
 * 【逐位精确保障(任何输入)】块内可容纳的元素数超过 255 时 u8 增量会回绕 ⇒ 建块基址时
 *   逐块检查 `c > 255`,一旦触发立刻转**与原件逐字节一致的回退路径**(memset(pref32) /
 *   4 字节逐值计数 / 前缀直写 pref32 / 同一查表趟);直方图回绕(单值出现 > 255 次)同样
 *   转该回退路径 —— 两条守卫与原件语义一致,只是把"总是 4 MB 表"换成"数据允许时用 1 MB 表"。
 *   本机对拍:n=1e6 / 999983 / 262145 / 100000 四组随机数据输出与原件 FNV 逐位一致。
 * ====================== */
#include <immintrin.h>
#include <cstring>
#include <cstdint>
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi2,popcnt")
/* [R2F2-P8] u8 block-delta ranks: pref8[v] = rank(v) - base[v>>7], 128-value blocks.
   rank(v) = number of points with coordinate < v.  The gather working set drops
   from 4 MB (u32 ranks) to 1 MB (u8 deltas) + 32 KB block bases. */
static unsigned char hist[100000000];
alignas(64) static unsigned char pref8[100000000 + 64];
alignas(64) static unsigned base128[1048576 + 64];
alignas(64) static unsigned pref32[100000016];

void count_1d(int n,const unsigned*x,unsigned*out){
 std::memset(hist,0,(size_t)n);
 bool wide=false;
 for(int i=0;i<n;i++){
  if(i+64<n)__builtin_prefetch(hist+x[i+64],1,3);
  if(++hist[x[i]]==0){wide=true;break;}
 }
 if(!wide){
  const int NB=(n+127)>>7;
  unsigned s=0; bool ovf=false;
  for(int b=0;b<NB;b++){
   int e=(b<<7)+128; if(e>n)e=n;
   unsigned c=0; for(int j=b<<7;j<e;j++)c+=hist[j];
   base128[b]=s;
   if(c>255){ovf=true;break;}
   s+=c;
  }
  if(!ovf){
   /* vectorized u8 delta scan (exclusive ranks, u8 packed) */
   __m256i carry=_mm256_setzero_si256();int i=0;
   for(;i+8<=n;i+=8){
    const unsigned bs=base128[i>>7];
    __m256i raw=_mm256_cvtepu8_epi32(_mm_loadl_epi64((const __m128i*)(hist+i)));
    __m256i v=raw;
    v=_mm256_add_epi32(v,_mm256_slli_si256(v,4));
    v=_mm256_add_epi32(v,_mm256_slli_si256(v,8));
    __m256i low=_mm256_permute2x128_si256(v,v,0x08);
    low=_mm256_shuffle_epi32(low,0xff);
    v=_mm256_add_epi32(v,low);
    __m256i total=_mm256_permutevar8x32_epi32(v,_mm256_set1_epi32(7));
    __m256i res=_mm256_sub_epi32(_mm256_add_epi32(v,carry),raw);
    __m256i d=_mm256_sub_epi32(res,_mm256_set1_epi32((int)bs));
    __m256i sh=_mm256_shuffle_epi8(d,_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));
    uint32_t w0=(uint32_t)_mm_cvtsi128_si32(_mm256_castsi256_si128(sh));
    uint32_t w1=(uint32_t)_mm_cvtsi128_si32(_mm256_extracti128_si256(sh,1));
    std::memcpy(pref8+i,&w0,4);
    std::memcpy(pref8+i+4,&w1,4);
    carry=_mm256_add_epi32(carry,total);
   }
   unsigned s2=(unsigned)_mm256_extract_epi32(carry,0);
   for(;i<n;i++){pref8[i]=(unsigned char)(s2-base128[i>>7]);s2+=hist[i];}
   for(int k=0;k<n;k++){
    if(k+64<n)__builtin_prefetch(pref8+x[k+64],0,3);
    out[k]=base128[x[k]>>7]+pref8[x[k]];
   }
   return;
  }
 }
 /* fallback: the rank-1 wide path (u32 ranks), byte-for-byte the master's semantics */
 std::memset(pref32,0,(size_t)n*sizeof(unsigned));
 for(int i=0;i<n;i++)++pref32[x[i]];
 {unsigned s=0;for(int i=0;i<n;i++){unsigned c=pref32[i];pref32[i]=s;s+=c;}}
 for(int i=0;i<n;i++){
  if(i+64<n)__builtin_prefetch(pref32+x[i+64],0,3);
  out[i]=pref32[x[i]];
 }
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #15.19 ms5 MB + 796 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-10-27 06:47:33 | Loaded in 2 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠