提交记录 104213


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_cc_v41_agg1 noi18c. 【NOI2018】你的名字 Accepted 100 138.447 ms 138256 KB C++11 20.79 KB
提交时间 评测时间
2026-09-28 06:49:08 2026-09-28 06:49:20
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6s_agg2,提交 #103842 <https://duck.ac/submission/103842>
//     (本题当前榜首)用途:**直接复制**了对方相对我们 #99767 的两处改动,逐字节复刻:
//     (a) SAM(T) 的转移表 t_nxt 3 字节打包(u8 t_nxt[(2*MAXT+10)*80]、3 字节偏移上的 4 字节
//         load + &0xFFFFFF / 4 字节读-改-写、tzero 5 条对齐 16B store、clone memcpy 104->80 B);
//     (b) 区间最大值的块长 `EBS 32 -> 8`(`EBSH 5 -> 3`)。
//     本地归档:problems/noi18c/ref2/rival_103842.cpp
// [2] duck.ac 用户 saffah_cc_v41_260924,提交 #103996 <https://duck.ac/submission/103996>
//     用途:直接复制了本文件的原型(我们自己的最好件 problems/noi18c/work/n1b_sub1.cpp),
//     含 s_nxt 的 20 位/65 字节行打包与「计数排序代替 len 桶链表」。
// [3] duck.ac 用户 saffah_cc_v41_260924,提交 #99767 <https://duck.ac/submission/99767>
//     用途:直接复制了 s_nxt 3 字节打包与 sget/sset 的 4 字节读-改-写手法(血统)。
// [4] duck.ac 用户 saffah_cc_v41_260924,提交 #87737 <https://duck.ac/submission/87737>
//     用途:直接复制了本题的全部算法与代码骨架(SAM(S)/SAM(T)、后缀链接树 Euler 区间、
//     按 r 单调激活、区间最大值查询流程、输入解析与输出格式)。
// [5] duck.ac 用户 saffah_cc_v41_260924,提交 #99553 <https://duck.ac/submission/99553>
//     用途:**参考了思想**(不是复制代码)——「纯分块扫描 + 两级块和」的区间最大值结构。
// [6] duck.ac 用户 saffah_cc_v41_260924,提交 #99482 <https://duck.ac/submission/99482>
//     用途:**参考了思想** —— Euler 区间惰性构造。
// 以上均为公开提交,未见附带的许可证声明;此处按「作者账号 + 原始提交地址 + 所用内容」逐条注明。
// ======================
// ===== 思路 =====
// 【实测到的 tc17 阶段分解】PHASE 前缀版 #104011/#104013/#104019/#104032/#104037 逐点相减:
//   tc17 = 140.018 ms = 解析+SAM(S) 35.28 | build_ord+build_meta 4.00 | 匹配 f[] 85.63
//                       | SAM(T)+累加 13.78 | emit 0.54
//   ⇒ 匹配占 61%。它是一条**串行**随机访存链(`sget(v,c)` → `s_link[v]` → …),
//     每次都要落到 39 MB 的 s_nxt / 2.4 MB 的 s_len / s_link / mxo 上,
//     所以「**少一次随机访存**」就是这一阶段唯一的有效方向。
//   (实测反证:把 SAM(T) 融合进匹配循环想靠 MLP 掩盖延迟 —— 反而 +1.1 ms;本族是
//     「访存条数/足迹」瓶颈,不是「等不到并发」瓶颈。)
//
// 【本提交的三处改动】
// (1) **匹配回退链里去掉每次 rung 的 `s_len[v]` 读**(本轮的主刀)。
//     原式 `while(v!=1 && !sget(v,c)){ v = s_link[v]; len = s_len[v]; }` 在**每一级**都把
//     `len` 重写一遍,但 `len` 只在循环**之后**被读;且只要走过至少一级,循环结束时
//     `len == s_len[v]`(v 是那一级之后的 v)。⇒ 把 `s_len[]` 的读挪到循环外只读一次:
//         { int ov=v; while(v!=1 && !sget(v,c)) v = s_link[v]; if(v != ov) len = s_len[v]; }
//     语义逐位不变(走过 0 级时 len 保持原值,与原来一致),但每走一级省掉一次
//     **对另一条 2.4 MB 数组**的随机访存(多一个 TLB 项、多一次 miss)。
//     循环后那句 `sget(v,c)` 与回退链最后一次测试的是同一地址,是 L1 命中,保留不动。
// (2) **`szsub[]` 的初始化从 SAM 构造推迟到 build_intervals**:szsub 只被 build_intervals 读,
//     在 eul_ready=0 的测试点上那 600000 次 `szsub[cur]=1` 纯属浪费(白碰 2.4 MB 页)。
// (3) **emit 换成两位查表**(100 项 '00'..'99' 常量表),12 位答案由 12 次除法降到 6 次。
//
// 【正确性】本地 101 组数据(|S| 到 500000、s_sz 到 999959、2/4/7/26 字母、周期串、
// l=1,r=|S|(eul_ready=0)与随机 l,r(eul_ready=1)、Σ|T|≈1e6、Q=1..1000、
// 以及答案 0/1/2/3 的 emit 边界)与 #99767 输出**逐字节一致**。
// 本次为正式提交:直接冲击达标线。
// ================
// NOI2018 你的名字  --  JudgeDuck (MAIN style)

#include <string.h>
#include <stdint.h>
#include <immintrin.h>

#pragma GCC push_options
#pragma GCC target("avx2,popcnt,bmi,bmi2")

typedef unsigned char u8;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef unsigned long ul;

struct DI {
  ul abi; const char*ip; ul is; char*op; ul ol,os; char*ep; ul el,es;
  const char*IBp; ul IBl; char*OBp; ul OBl; ul tsc;
} __attribute__((packed));

#define MAXS 500005
#define MAXST 1000016
#define MAXQ 100005
#define MAXT 1000008
#define MAXTT 2000016

static u32 bhead[MAXS+8], szsub[MAXST], nxt[MAXST];   // bhead = len histogram -> start offsets
static u32 tin[MAXST], tout[MAXST], mxo[MAXST];
static u32 ord_[MAXST]; static int nord_;   // len-descending state order (lazy-Euler)
static int eul_ready;
// ancestor painting (see 思路): wl_last[x] = max own+1 among activated prefix-states
// whose suffix-link path passes through x  ==  MX(x, r) exactly.
static u32 wl_last[MAXST];
static int wl_mode; static long long wl_budget;
// per-query paint-back scratch: zeroing only the states we painted keeps the
// reset O(sz) instead of O(MAXST) between queries.
static u32 plist_[MAXST];

// ======================= SAM of S (dense 26-way transitions) ==============
// transitions of state p are at s_nxt[p*26 .. p*26+26); every state index is
// used once per process, so BSS stays zero and fresh states have no transitions.
// Transitions packed as 24-bit little-endian words: 26*3 = 78 B per state instead of
// 26*4 = 104 B.  State ids are <= 2*MAXS+8 < 2^24, so 24 bits are lossless.
// BUDGET (tc17: s_sz=661320) -- MEASURED sizes, not guesses:
//   touched footprint 65.6 MB -> 49.2 MB (-16.4 MB) = -4197 first-touch pages.
//   At the measured 244 ns/page that alone is -1.02 ms, and every sget in the SAM
//   construction and in the match loop additionally reads a 25%-smaller random
//   working set (better TLB reach), which is the part that should pay off more.
// COST: sget gains one AND; sset becomes a 4-byte read-modify-write (the extra byte
//   read back is the *next* entry's low byte and is written back unchanged, so
//   neighbours are preserved) = ~+3..5 uops per access.  Reads use a 4-byte load at
//   the 3-byte offset, so the array carries 10 spare rows of padding.
/* --- s_nxt: 20-bit packed transitions (row = 26*20 bits = 65 bytes) ---------
   State ids are <= 2*MAXS+8 = 1000018 < 2^20, so 20 bits are lossless.
   Row stride 65 B instead of 78 B (-17% footprint on the dominant table).
   Entry c of row p starts at bit 20c; (20c)&7 == 4*(c&1) is always 0 or 4, so a
   single unaligned 8-byte load at byte ((5c)>>1) always contains the entry. */
static u8 s_nxt[(2*MAXS+10)*65 + 16];
static u32 s_len[MAXST], s_link[MAXST];
static int s_sz, s_last;
static u32 s_own[MAXS];
#define S20_MASK 0xFFFFFu
static inline int sget(int p, int c){
  size_t off = (size_t)p*65 + (size_t)(((unsigned)c*5u)>>1);
  u32 x; __builtin_memcpy(&x, s_nxt + off, 4);
  return (int)((x >> (((unsigned)c&1u)<<2)) & S20_MASK);
}
static inline void sset(int p, int c, int t){
  size_t off = (size_t)p*65 + (size_t)(((unsigned)c*5u)>>1);
  u32 x; __builtin_memcpy(&x, s_nxt + off, 4);
  unsigned sh = ((unsigned)c&1u)<<2;
  x = (x & ~(S20_MASK << sh)) | (((u32)t & S20_MASK) << sh);
  __builtin_memcpy(s_nxt + off, &x, 4);
}
static void build_sam_s(const char* S, int n){
  s_sz = 1; s_last = 1;
  s_len[1] = 0; s_link[1] = 0;
  memset(bhead, 0, (size_t)(n+2)*4);
  for(int i=0;i<n;i++){
    int c = S[i]-'a';
    int cur = ++s_sz;
    s_len[cur] = s_len[s_last]+1;
    bhead[s_len[cur]]++;
    mxo[cur] = (u32)(i+1);
    s_own[i] = (u32)cur;
    int p = s_last;
    for(; p && !sget(p,c); p = (int)s_link[p]) sset(p,c,cur);
    if(!p) s_link[cur] = 1;
    else {
      int q = sget(p,c);
      if((int)s_len[p]+1 == (int)s_len[q]) s_link[cur] = (u32)q;
      else {
        int cl = ++s_sz;
        s_len[cl] = s_len[p]+1; s_link[cl] = s_link[q];
        bhead[s_len[cl]]++;
        mxo[cl] = 0;
        memcpy(s_nxt + (size_t)cl*65, s_nxt + (size_t)q*65, 65);
        for(; p && sget(p,c)==q; p = (int)s_link[p]) sset(p,c,cl);
        s_link[q] = (u32)cl; s_link[cur] = (u32)cl;
      }
    }
    s_last = cur;
  }
}

// ======================= SAM of T, rebuilt per query (dense) ==============
static u8 t_nxt[(2*MAXT+10)*80] __attribute__((aligned(16)));
static u32 t_len[MAXTT], t_link[MAXTT];
static int t_sz, t_last;
static inline int tget(int p, int c){
  u32 x; __builtin_memcpy(&x, t_nxt + (size_t)p*80 + (size_t)c*3, 4);
  return (int)(x & 0xFFFFFFu);
}
static inline void tset(int p, int c, int t){
  size_t off = (size_t)p*80 + (size_t)c*3;
  u32 x; __builtin_memcpy(&x, t_nxt + off, 4);
  x = (x & 0xFF000000u) | ((u32)t & 0xFFFFFFu);
  __builtin_memcpy(t_nxt + off, &x, 4);
}
static inline void tzero(int p){
  u8* row = t_nxt + (size_t)p*80;
  __m128i z = _mm_setzero_si128();
  _mm_store_si128((__m128i*)(row+0), z);
  _mm_store_si128((__m128i*)(row+16), z);
  _mm_store_si128((__m128i*)(row+32), z);
  _mm_store_si128((__m128i*)(row+48), z);
  _mm_store_si128((__m128i*)(row+64), z);
}

// ============ suffix-link tree: len-bucket lists + two linear passes ======

static int s_sn;

// ---- counting sort of the states by len (replaces the bucket linked list) ----
// ord_ ends up len-ASCENDING, so pass 1 (bottom-up mxo) walks it backwards and
// pass 2 (top-down preorder) walks it forwards.  No linked list => no serial
// pointer chase in the sweep, and no random write per state during construction.
static void build_ord(void){
  int n = s_sn;
  u32 sum = 0;
  for(int L=0; L<=n; L++){ u32 c = bhead[L]; bhead[L] = sum; sum += c; }
  for(u32 v=1; v<=(u32)s_sz; v++){ ord_[bhead[s_len[v]]++] = v; }
  nord_ = (int)sum;
}
// Pass 1 (ALWAYS needed): mxo[v] = max own+1 over the subtree of v, by a
// len-descending sweep (children strictly before parents).  The same sweep
// records the visiting order into ord_[] (sequential stores), so pass 2 never
// has to re-walk the bucket chains.
static void build_meta(void){          // bottom-up: children (larger len) first
  for(int i = nord_-1; i >= 0; i--){
    u32 v = ord_[i];
    u32 p = s_link[v];
    if(p && mxo[v] > mxo[p]) mxo[p] = mxo[v];
  }
}
// Pass 2 (LAZY): subtree sizes + preorder numbers.  Only the range-max over
// [tin,tout) uses these, so they are built at the first query that actually
// needs a range-max.  ord_[] is len-descending, so forward = bottom-up sizes,
// backward = top-down preorder.
static void build_intervals(void){
  // szsub[] is initialised here instead of in build_sam_s: it is only ever read by
  // this function, so the per-state store in the construction loop (and the 2.4 MB of
  // pages it dirtied) is pure overhead on tests that never build the intervals.
  for(int i=0;i<nord_;i++) szsub[ord_[i]] = 1;
  szsub[1] = 0;   // state 1's size is never read (its link is 0), exactly as before
  for(int i=nord_-1;i>=0;i--){          // len-descending = bottom-up sizes
    u32 v = ord_[i]; u32 p = s_link[v];
    if(p) szsub[p] += szsub[v];
  }
  tin[1] = 1; nxt[1] = 2;
  for(int i=0;i<nord_;i++){             // len-ascending = parents first = preorder
    u32 v = ord_[i];
    if(v == 1) continue;
    u32 p = s_link[v];
    u32 t = nxt[p];
    tin[v] = t; tout[v] = t + szsub[v];
    nxt[p] = t + szsub[v];
    nxt[v] = t + 1;
  }
}

// ============ range max over the Euler array (fused block scans) ============
// Replaces the earlier "block prefix/suffix arrays + segment tree over blocks".
// MEASURED on the real judge (tools/probe.py, n=5e5 random 26-letter S, cycles):
//   old eactivate  70.15M   old build_meta 15.58M  old build_intervals 22.38M
//   old qmax ~96 cyc/call
// The old activation wrote a whole 64-entry prefix block AND a whole 64-entry
// suffix block per activation (512 B = 8 cache lines of RFO traffic), plus a
// 15-level segment-tree update -- 140 cycles per activation.  With plain block
// scans the activation is 3 stores (one cold, two L1-resident) and the segment
// tree disappears.
#define EBS 8
#define EBSH 3
#define GBS 128
#define GBSH 7
#define ENB ((MAXST>>EBSH)+8)
#define ESB ((ENB>>GBSH)+8)
static u32 ev[MAXST+8];
static u32 ebmax[ENB+8];
static u32 eb2[ESB+8];

static inline void eactivate(int leaf, u32 val){
  ev[leaf] = val;
  int b = leaf >> EBSH;
  ebmax[b] = val;
  eb2[b >> GBSH] = val;
}
#define AVX2T __attribute__((target("avx2")))
AVX2T static inline __m256i ldu256(const void *p){
  __m256i r; __asm__("vmovdqu %1, %0" : "=x"(r) : "m"(*(const __m256i *)p)); return r; }
// accumulate max over p[0..n) into acc for ANY n>=0 (n<8 must not use the
// overlapping tail load -- it would read BEFORE p and pick up foreign values)
AVX2T static inline __m256i accblk(__m256i acc, const u32* p, int n){
  if(n <= 0) return acc;
  if(n < 8){
    for(int i=0;i<n;i++) acc = _mm256_max_epu32(acc, _mm256_set1_epi32((int)p[i]));
    return acc;
  }
  int i = 0;
  for(; i+8 <= n; i += 8) acc = _mm256_max_epu32(acc, ldu256(p+i));
  if(i < n) acc = _mm256_max_epu32(acc, ldu256(p+n-8));   // overlapping tail load
  return acc;
}
AVX2T static inline u32 red256(__m256i acc){
  __m128i lo = _mm256_castsi256_si128(acc), hi = _mm256_extracti128_si256(acc,1);
  __m128i m = _mm_max_epu32(lo,hi);
  m = _mm_max_epu32(m, _mm_shuffle_epi32(m,_MM_SHUFFLE(1,0,3,2)));
  m = _mm_max_epu32(m, _mm_shuffle_epi32(m,_MM_SHUFFLE(2,3,0,1)));
  return (u32)_mm_cvtsi128_si32(m);
}
AVX2T static inline u32 scanmax(const u32* p, int n){
  if(n <= 0) return 0;
  return red256(accblk(_mm256_setzero_si256(), p, n));
}
static inline u32 qmax(int l, int r){          // max over [l,r)
  if(l>=r) return 0;
  int b1=l>>EBSH, b2=(r-1)>>EBSH;
  if(b1==b2) return scanmax(ev+l, r-l);
  __m256i acc = _mm256_setzero_si256();
  acc = accblk(acc, ev+l, ((b1+1)<<EBSH) - l);
  int j = r & (EBS-1);
  if(j) acc = accblk(acc, ev+(b2<<EBSH), j);
  else  acc = accblk(acc, ebmax+b2, 1);
  int lo=b1+1, hi=b2, cnt=hi-lo;             // whole blocks [lo,hi)
  if(cnt > 0){
    if(cnt <= GBS){
      acc = accblk(acc, ebmax+lo, cnt);
    } else {
      int s1=(lo+GBS-1)&~(GBS-1), s2=hi&~(GBS-1);
      if(s1>lo) acc = accblk(acc, ebmax+lo, s1-lo);
      if(s2>s1) acc = accblk(acc, eb2+(s1>>GBSH), (s2-s1)>>GBSH);
      if(hi>s2) acc = accblk(acc, ebmax+s2, hi-s2);
    }
  }
  return red256(acc);
}

// ============================== query handling ============================
struct QE { const char* t; int tl, l, r, idx; };
static QE qs[MAXQ];
static QE qs2[MAXQ];
static long long answers[MAXQ];
static int f_[MAXS];
static int cnt_[MAXS+2];

static char* OUTP;
static const char D2[201] =
  "00010203040506070809101112131415161718192021222324252627282930313233343536373839"
  "40414243444546474849505152535455565758596061626364656667686970717273747576777879"
  "8081828384858687888990919293949596979899";
static inline void emit(long long v){
  char b[24]; int c=0;
  if(v==0){ *OUTP++='0'; *OUTP++='\n'; return; }
  while(v >= 100){
    unsigned r = (unsigned)(v % 100); v /= 100;
    b[c++] = D2[r*2+1]; b[c++] = D2[r*2];
  }
  if(v >= 10){ unsigned r = (unsigned)v; b[c++] = D2[r*2+1]; b[c++] = D2[r*2]; }
  else if(v > 0){ b[c++] = (char)('0' + (int)v); }
  while(c) *OUTP++ = b[--c];
  *OUTP++='\n';
}

static void run(const u8* in, ul insz, char* out){
  const char* p = (const char*)in;
  const char* e = p + insz;
  OUTP = out;

  while(p<e && (*p<'a'||*p>'z')) p++;
  const char* sstart = p;
  while(p<e && *p>='a'&&*p<='z') p++;
  int sn = (int)(p - sstart);
  build_sam_s(sstart, sn);

  while(p<e && (*p<'0'||*p>'9')) p++;
  int Q=0;
  while(p<e && *p>='0'&&*p<='9'){ Q = Q*10 + (*p-'0'); p++; }
  if(Q>MAXQ) Q=MAXQ;

  for(int i=0;i<Q;i++){
    while(p<e && (*p<'a'||*p>'z')) p++;
    const char* ts = p;
    while(p<e && *p>='a'&&*p<='z') p++;
    int tl = (int)(p-ts);
    if(tl>MAXT) tl=MAXT;
    while(p<e && (*p<'0'||*p>'9')) p++;
    int l=0; while(p<e && *p>='0'&&*p<='9'){ l=l*10+(*p-'0'); p++; }
    while(p<e && (*p<'0'||*p>'9')) p++;
    int r=0; while(p<e && *p>='0'&&*p<='9'){ r=r*10+(*p-'0'); p++; }
    qs[i].t = ts; qs[i].tl = tl; qs[i].l = l; qs[i].r = r; qs[i].idx = i;
  }

  s_sn = sn;
  int sz = s_sz;
  // ---- strategy choice ---------------------------------------------------
  // The ancestor-painting routes are KEPT in the file but no longer selected:
  // real-judge measurement showed their cost is sum_i depth(s_own[i]) steps, which
  // the 256-sample estimate can under-predict (a deep tree blows it up ~4x), while
  // the Euler route is now bounded and cheap: with the block-scan activation its
  // fixed cost is 34 cyc/state (intervals) + 20 cyc/activation + 113 cyc/qmax.
  // Forcing the Euler route makes the tree phase predictable instead of data-dependent.
  wl_mode = 0; wl_budget = 0;
  build_ord();
  if(!wl_mode) build_meta();
  eul_ready = 0;
  // ev / ebmax / etree are zero initialized (BSS): no clearing needed

  { // counting sort of the queries by r
    int mx = sn+1;
    memset(cnt_, 0, (size_t)(mx+2)*4);
    for(int i=0;i<Q;i++){ int rr = qs[i].r; if(rr<0) rr=0; if(rr>mx) rr=mx; cnt_[rr]++; }
    int acc=0;
    for(int i=0;i<=mx;i++){ int c=cnt_[i]; cnt_[i]=acc; acc+=c; }
    for(int i=0;i<Q;i++){ int rr = qs[i].r; if(rr<0) rr=0; if(rr>mx) rr=mx; qs2[cnt_[rr]++] = qs[i]; }
  }

  int act = 0;   // positions < act already activated
  long long wl_work = 0;
  for(int qi=0; qi<Q; qi++){
    const QE& q = qs2[qi];
    int need = q.r;                 // activate positions 0..r-1
    if(need > sn) need = sn;
    if(need < 0) need = 0;
    int npaint = 0;
    if(wl_mode == 2){
      // downward sweep, stop at the first state already painted this query:
      // the first state painted gets the largest own+1, which is exactly MX(x, need)
      for(int i=need-1;i>=0;i--){
        int a = (int)s_own[i]; u32 val = (u32)(i+1);
        while(a != 1 && !wl_last[a]){ wl_last[a] = val; plist_[npaint++] = (u32)a; a = (int)s_link[a]; }
      }
    } else if(wl_mode){
      for(; act<need; act++){
        int a = (int)s_own[act]; u32 val = (u32)(act+1);
        wl_last[a] = val; wl_work++;
        while(a != 1){ a = (int)s_link[a]; wl_last[a] = val; wl_work++; }
        if(wl_work > wl_budget){ wl_mode = 0; break; }   // blew the budget
      }
      if(!wl_mode){                 // fell back mid-activation: replay into the Euler struct
        build_meta(); build_intervals(); eul_ready = 1;
        for(int i=0;i<act;i++){ int v = (int)s_own[i]; eactivate((int)tin[v], (u32)(i+1)); }
        for(; act<need; act++){ int v = (int)s_own[act]; eactivate((int)tin[v], (u32)(act+1)); }
      }
    } else if(eul_ready){
      for(; act<need; act++){
        int v = (int)s_own[act];
        eactivate((int)tin[v], (u32)(act+1));
      }
    } else if(need > act) act = need;
    const char* T = q.t;
    int tl = q.tl;
    int l0 = q.l - 1;
    int r1 = q.r - 1;
    int maxlen = q.r - q.l + 1;
    if(maxlen < 0) maxlen = 0;
    int v = 1, len = 0, e = -1;   // e = witness end position of the current match
    for(int i=0;i<tl;i++){
      int c = T[i]-'a';
      // fast path: the match extends in place at the witness (f[i] <= f[i-1]+1, so len+1 is optimal)
      if(len > 0 && e < r1 && sstart[e+1]-'a' == c){
        v = sget(v,c); len++; e++;
        f_[i] = len;
        continue;
      }
      // Only the FINAL rung of this walk matters: `len` is rewritten on every step
      // but read only after the loop, and once at least one step ran len == s_len[v].
      // Reading s_len[] inside the loop therefore costs one extra random load per rung
      // into a *separate* 2.4 MB array (one more TLB entry + one more miss) for
      // nothing.  The sget below is the very address the walk just tested => L1 hit.
      {
        int ov = v;
        while(v!=1 && !sget(v,c)) v = (int)s_link[v];
        if(v != ov) len = (int)s_len[v];
      }
      int nx = sget(v,c);
      if(nx){ v = nx; len++; } else { v = 1; len = 0; }
      e = -1;
      // clip the match to S[l..r]: longest suffix whose endpos hits [l+len-1, r-1]
      while(len>0){
        if(len > maxlen){
          len = maxlen;
          while(v != 1 && len <= (int)s_len[s_link[v]]) v = (int)s_link[v];
          if(len == 0) break;
        }
        u32 m;
        if(mxo[v] <= (u32)q.r) m = mxo[v];
        else {
          if(!eul_ready){
            build_intervals();
            for(int i2=0;i2<act;i2++){ int vv=(int)s_own[i2]; eactivate((int)tin[vv], (u32)(i2+1)); }
            eul_ready = 1;
          }
          m = qmax((int)tin[v],(int)tout[v]);
        }
        // lengths in this state's class that can still satisfy the test
        int lim = (int)m - l0;
        if(lim >= len){ e = (int)m - 1; break; }
        int pl = (int)s_len[s_link[v]];
        if(lim > pl){ len = lim; e = (int)m - 1; break; }
        len = pl;
        if(len == 0) break;
        v = (int)s_link[v];
      }
      f_[i] = len;
    }
    if(wl_mode == 2){ for(int k=0;k<npaint;k++) wl_last[plist_[k]] = 0; }
    // SAM(T) -> g[], accumulate
    t_sz=1; t_last=1;
    t_len[1]=0; t_link[1]=0;
    tzero(1);
    long long ans=0;
    for(int i=0;i<tl;i++){
      int c = T[i]-'a';
      int cur = ++t_sz;
      t_len[cur] = t_len[t_last]+1; t_link[cur]=0;
      tzero(cur);
      int pp = t_last;
      for(; pp && !tget(pp,c); pp = (int)t_link[pp]) tset(pp,c,cur);
      int lk;
      if(!pp) lk = 1;
      else {
        int qq = tget(pp,c);
        if((int)t_len[pp]+1 == (int)t_len[qq]) lk = qq;
        else {
          int cl = ++t_sz;
          t_len[cl] = t_len[pp]+1; t_link[cl] = t_link[qq];
          memcpy(t_nxt + (size_t)cl*80, t_nxt + (size_t)qq*80, 80);
          for(; pp && tget(pp,c)==qq; pp = (int)t_link[pp]) tset(pp,c,cl);
          t_link[qq] = (u32)cl; lk = cl;
        }
      }
      t_link[cur] = (u32)lk;
      t_last = cur;
      int g = (int)t_len[lk];
      int m = g > f_[i] ? g : f_[i];
      ans += (long long)(i+1) - m;
    }
    answers[q.idx] = ans;
  }
  for(int i=0;i<Q;i++) emit(answers[i]);
}

#pragma GCC pop_options

#ifndef LOCAL
int main(){ return 0; }
extern "C" void __libc_start_main(void*mm,int argc,char**argv){
  ul *p=(ul*)(argv+argc+1);
  while(*p) p++; p++;
  DI *d=0; for(; p[0]; p+=2) if(p[0]==0x6b637564UL){ d=(DI*)p[1]; break; }
  if(d){
    const u8* in=(const u8*)d->IBp; ul insz=d->IBl;
    if(!insz && d->is){ in=(const u8*)d->ip; insz=d->is; }
    run(in,insz,d->op);
    d->os=(ul)(OUTP-d->op);
  }
  __asm__ volatile("syscall"::"a"(60),"D"(0):"rcx","r11","memory");
  for(;;);
}
#endif

CompilationN/AN/ACompile OKScore: N/A

Testcase #11.162 ms148 KBAcceptedScore: 4

Testcase #21.27 ms252 KBAcceptedScore: 4

Testcase #31.333 ms260 KBAcceptedScore: 4

Testcase #416.61 ms592 KBAcceptedScore: 4

Testcase #516.017 ms576 KBAcceptedScore: 4

Testcase #677.153 ms135 MB + 16 KBAcceptedScore: 4

Testcase #776.847 ms134 MB + 1020 KBAcceptedScore: 4

Testcase #811.674 ms15 MB + 1004 KBAcceptedScore: 4

Testcase #913.722 ms13 MB + 712 KBAcceptedScore: 4

Testcase #1026.421 ms30 MB + 112 KBAcceptedScore: 4

Testcase #1133.565 ms27 MB + 128 KBAcceptedScore: 4

Testcase #1243.488 ms44 MB + 76 KBAcceptedScore: 4

Testcase #1361.847 ms41 MB + 28 KBAcceptedScore: 4

Testcase #1462.742 ms58 MB + 520 KBAcceptedScore: 4

Testcase #1597.515 ms55 MB + 236 KBAcceptedScore: 4

Testcase #1683.669 ms72 MB + 968 KBAcceptedScore: 4

Testcase #17138.447 ms69 MB + 560 KBAcceptedScore: 4

Testcase #1874.434 ms42 MB + 836 KBAcceptedScore: 4

Testcase #1987.34 ms57 MB + 200 KBAcceptedScore: 4

Testcase #20104.803 ms71 MB + 848 KBAcceptedScore: 4

Testcase #21114.306 ms86 MB + 976 KBAcceptedScore: 4

Testcase #22123.895 ms86 MB + 852 KBAcceptedScore: 4

Testcase #23122.005 ms86 MB + 808 KBAcceptedScore: 4

Testcase #24116.307 ms86 MB + 948 KBAcceptedScore: 4

Testcase #25114.938 ms86 MB + 984 KBAcceptedScore: 4


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