提交记录 108801


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_cc_v41_260924 noi18c. 【NOI2018】你的名字 Accepted 100 134.808 ms 231284 KB C++17 16.32 KB
提交时间 评测时间
2026-09-29 02:02:14 2026-09-29 02:02:22
// NOI2018 你的名字  --  JudgeDuck (MAIN style)
//
//   answer = sum_j (j - max(g[j], f[j]))      (j 1-based)
//     f[j] = longest suffix of T[1..j] that occurs inside S[l..r]
//     g[j] = longest suffix of T[1..j] that occurs earlier inside T
//
//   f[]: walk T through SAM(S).  endpos(v) = { own(u) : u in subtree(v) } of the
//        suffix-link tree, so the clamp test
//            "endpos(v) meets [l+len-1, r-1]"
//        becomes  max{ own(u)+1 : u in subtree(v), own(u) <= r-1 } >= l+len .
//        Queries are processed in increasing r, so "own(u) <= r-1" is a monotone
//        point activation; the test is a range-max over the DFS-Euler interval
//        (block + segment tree over blocks, all cache resident).
//   g[]: online SAM construction of T, recording len[link[cur]] at creation.
//
#include <string.h>
#include <stdint.h>
#include <immintrin.h>

#pragma GCC push_options
#pragma GCC target("avx2,popcnt,bmi,bmi2")
#pragma GCC optimize("O3")
#pragma GCC optimize("align-functions=64","align-loops=32")
#pragma GCC optimize("ira-loop-pressure")
#pragma GCC optimize("sched-stalled-insns=4")

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

#define AVX2 __attribute__((target("avx2")))
AVX2 static inline __m256i ldu256(const void *p){
  __m256i r; __asm__("vmovdqu %1, %0" : "=x"(r) : "m"(*(const __m256i *)p)); return r; }


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

// ======================= 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.
static u32 s_nxt[(2*MAXS+8)*32];   /* CS1 ROW32 */
static u32 s_len[MAXST], s_link[MAXST];
static int s_sz, s_last;
static u32 s_own[MAXS];
static inline int sget(int p, int c){ return (int)s_nxt[(size_t)p*32 + c]; }
static inline void sset(int p, int c, int t){ s_nxt[(size_t)p*32 + c] = (u32)t; }
static void build_sam_s(const char* S, int n){
  s_sz = 1; s_last = 1;
  s_len[1] = 0; s_link[1] = 0;
  for(int i=0;i<n;i++){
    int c = S[i]-'a';
    int cur = ++s_sz;
    s_len[cur] = (u32)(i+1);
    s_own[i] = (u32)cur;
    int p = s_last, q = 0;
    sset(p,c,cur);
    p = (int)s_link[p];
    for(; p && !(q = sget(p,c)); p = (int)s_link[p]) sset(p,c,cur);
    int lp68 = (int)s_len[p], lq68 = (int)s_len[q];   /* CN1 SH68 */
    if(!p) s_link[cur] = 1;
    else {
      if(lp68+1 == lq68) s_link[cur] = (u32)q;
      else {
        int cl = ++s_sz;
        s_len[cl] = s_len[p]+1; s_link[cl] = s_link[q];
        memcpy(s_nxt + (size_t)cl*32, s_nxt + (size_t)q*32, 26*4);
        // D4: the walk above exited BECAUSE s_nxt[p][c]==q, and nothing wrote
        // s_nxt[p][c] since (the memcpy writes cl's row, len/link are other arrays),
        // so the shipped re-walk's first test is a known-answer TRUE.
        sset(p,c,cl); p = (int)s_link[p];
        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 u32 t_nxt[(2*MAXT+8)*32];   /* CS1 ROW32 */
static u32 t_len[MAXTT], t_link[MAXTT];
static int t_sz, t_last;
static inline int tget(int p, int c){ return (int)t_nxt[(size_t)p*32 + c]; }
static inline void tset(int p, int c, int t){ t_nxt[(size_t)p*32 + c] = (u32)t; }
static inline void tzero(int p){
  u32* row = t_nxt + (size_t)p*32;
  __m256i z = _mm256_setzero_si256();
  _mm256_storeu_si256((__m256i*)row, z);
  _mm256_storeu_si256((__m256i*)(row+8), z);
  _mm256_storeu_si256((__m256i*)(row+16), z);
  _mm_storeu_si128((__m128i*)(row+24), _mm_setzero_si128());
}

// ================= suffix-link tree: DFS Euler intervals ==================
static u32 c_cnt[MAXST+2], c_id[MAXST];
// ONE u64 per state instead of three u32 arrays: tin (20b) | subtree-size (20b) | mxo (20b).
// 12 MB -> 8 MB of footprint AND one cache line per state access instead of three.
static u64 TM[MAXST];
#define TINMASK 0xFFFFFu
#define TIN(v)  ((int)(TM[v] & TINMASK))
#define TOUT(v) ((int)((TM[v] & TINMASK) + ((TM[v] >> 20) & TINMASK)))
#define MXO(v)  ((u32)(TM[v] >> 40))
static u32 wl_last[MAXST];      // per STATE: max(own+1) activated in this state's subtree
static u32 estk[3*MAXST];   // (state, cursor, parent-pending-max) frames -- the parent update is a HOT stack write, not a random mxo[par] RMW

static int s_sn;
static void build_euler(int sz){
  // ---- CSR of the suffix-link tree with a TWO-array counting sort --------------------
  // The classic form needs three random-walk arrays (count / start / cursor); here the
  // INCLUSIVE prefix sum is taken IN PLACE and the scatter walks states DOWNWARD, which
  // turns the prefix array itself into the high cursor.  After the scatter c_cnt[p] is
  // the START of p's child list and c_cnt[p+1] the END, so the cursor array disappears
  // too.  Two random arrays instead of three, 8 MB instead of 12 MB of concurrent
  // random-access state -- this is the row's LLC-miss driver.
  memset(c_cnt, 0, (size_t)(sz+2)*4);
  for(int v=2; v<=sz; v++) c_cnt[s_link[v]]++;
  u32 acc=0;
  for(int v=1; v<=sz; v++){ acc += c_cnt[v]; c_cnt[v] = acc; }
  c_cnt[sz+1] = acc;
  for(int v=sz; v>=2; v--){ u32 p = s_link[v]; c_id[--c_cnt[p]] = (u32)v; }
  // ---- subtree max of own()+1 : mxo is FRESH BSS, so its zero fill is deleted -------
  for(int i=0;i<s_sn;i++){ int v=(int)s_own[i]; u32 nv=(u32)(i+1); if(nv > (u32)(TM[v] >> 40)) TM[v] = (TM[v] & 0xFFFFFFFFFFULL) | ((u64)nv << 40); }
  // ---- DFS Euler tour over the CSR ---------------------------------------------------
  int timer=1; u32 sp=0;   // TM[1] written below with tin=0
  estk[0]=1; estk[1]=c_cnt[1]; estk[2]=0; sp=1;
  TM[1] = (u64)0;                        // own-max of the root is 0; tin=0
  while(sp){
    u32 *f = estk + 3*(sp-1);
    u32 v = f[0];
    u32 cur = f[1];
    if(cur < c_cnt[v+1]){
      int u = (int)c_id[cur];
      f[1] = cur+1;
      TM[u] = (TM[u] & ~(u64)TINMASK) | (u64)timer; timer++;
      u32 *g = estk + 3*sp;
      g[0]=(u32)u; g[1]=c_cnt[u]; g[2]=0; sp++;
    } else {
      u64 tv = TM[v];
      u32 m = (u32)(tv >> 40);
      if(f[2] > m) m = f[2];
      u32 sz = (u32)timer - (u32)(tv & TINMASK);
      TM[v] = (tv & TINMASK) | ((u64)sz << 20) | ((u64)m << 40);
      sp--;
      if(sp){ u32 *pf = estk + 3*(sp-1); if(m > pf[2]) pf[2] = m; }
    }
  }
}

// ============ range max over the Euler array (fused block scans) ============
#define EBS 128
#define EBSH 7
#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;
}
// 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)
AVX2 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;
}
AVX2 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);
}
AVX2 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 inline void emit(long long v){
  char b[24]; int c=0;
  if(v==0){ *OUTP++='0'; *OUTP++='\n'; return; }
  while(v){ b[c++] = (char)('0' + (int)(v%10)); v/=10; }
  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 -------------------------------------------------
  // "euler+qmax" costs a CSR+DFS over the whole tree (17.5 %) plus a ~197-cycle
  // range-max per character of T (25.8 %).  The ALTERNATIVE is to give the
  // answer directly:  last[a] = p+1 for every ANCESTOR a of s_own[p], written as
  // activations sweep p upward -- then m(v) = last[v] is ONE load.  Its cost is
  // sum_i depth(s_own[i]), which is 5.7 * 5e5 on a random S but 65 * 5e5 on a
  // PERIODIC one, so it is chosen from a depth SAMPLE and guarded by a work
  // budget; blowing the budget falls back to the incumbent path.
  long long wl_est = 0, wl_budget = 0;
  int wl_walk = 0;
  {
    int K = 256; long long s = 0; int bad = 0;
    for(int k=0;k<K;k++){
      int i = (int)((long long)k * s_sn / K);
      int v = (int)s_own[i], d = 1, cap = 8192;
      while(v != 1 && cap-- > 0){ v = (int)s_link[v]; d++; }
      if(cap <= 0){ bad = 1; break; }
      s += d;
    }
    wl_est = bad ? (long long)1 << 50 : (s / K) * (long long)s_sn;
    // MEASURED break-even: the walk costs ~17 cycles/step on a SHALLOW tree (avg
    // depth 5.7 -> 47.5 M cycles for 2.85 M steps) but ~44 cycles/step on a DEEP
    // one (avg depth 65 -> 1425 M cycles), because the chain is a dependent
    // random chase and stops overlapping.  It replaces ~269 M cycles of
    // build_euler+qmax, so it is accepted only for genuinely shallow trees.
    wl_walk = (wl_est < 10000000LL);
    wl_budget = 2 * wl_est + 2000000LL; if(wl_budget > 30000000LL) wl_budget = 30000000LL;
  }
  if(!wl_walk) build_euler(sz);
  // ev / ebmax / etree are zero initialized (BSS): no clearing needed

  for(int wl_attempt = 0; wl_attempt < 2; wl_attempt++){
  { // 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; int wl_blown = 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(wl_walk){
      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]; if(a!=1){ wl_last[a] = val; } wl_work++; }
        if(wl_work > wl_budget){ wl_blown = 1; break; }
      }
    } else {
      for(; act<need; act++){
        int v = (int)s_own[act];
        eactivate(TIN(v), (u32)(act+1));
      }
    }
    if(wl_blown) break;
    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;
      }
      // D3: when the loop exits on a nonzero test, the shipped `nx = sget(v,c)`
      // re-loads the ADDRESS IT JUST LOADED; keep the value instead.
      int nx;
      { int vn = (int)s_link[v]; int v0 = v;
        while(v!=1 && !(nx = sget(v,c))){ v = vn; vn = (int)s_link[v]; }
        if(v != v0) len = (int)s_len[v]; }
      if(v==1) 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(wl_walk) m = wl_last[v];
        else {
          u64 tv = TM[v];
          m = ((u32)(tv >> 40) <= (u32)q.r) ? (u32)(tv >> 40) : qmax((int)(tv & TINMASK), (int)((tv & TINMASK) + ((tv >> 20) & TINMASK)));
        }
        // lengths in this state's class that can still satisfy the test
        int lkv2 = (int)s_link[v];
        int pl = (int)s_len[lkv2];
        int lim = (int)m - l0;
        if(lim >= len){ e = (int)m - 1; break; }
        if(lim > pl){ len = lim; e = (int)m - 1; break; }
        len = pl;
        if(len == 0) break;
        v = lkv2;
      }
      f_[i] = len;
    }
    // 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;
      { int pn = (int)t_link[pp];
        for(; pp && !tget(pp,c); pp = pn){ tset(pp,c,cur); pn = (int)t_link[pp]; } }
      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*32, t_nxt + (size_t)qq*32, 26*4);
          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;
  }
  if(!wl_blown) break;
  wl_walk = 0;
  build_euler(sz);
  }
  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
/*padO:#################################################################################################*/

CompilationN/AN/ACompile OKScore: N/A

Testcase #11.107 ms176 KBAcceptedScore: 4

Testcase #21.194 ms348 KBAcceptedScore: 4

Testcase #31.248 ms352 KBAcceptedScore: 4

Testcase #416.524 ms860 KBAcceptedScore: 4

Testcase #515.929 ms844 KBAcceptedScore: 4

Testcase #6133.767 ms225 MB + 884 KBAcceptedScore: 4

Testcase #7133.347 ms225 MB + 796 KBAcceptedScore: 4

Testcase #823.645 ms25 MB + 712 KBAcceptedScore: 4

Testcase #913.914 ms21 MB + 704 KBAcceptedScore: 4

Testcase #1042.75 ms48 MB + 264 KBAcceptedScore: 4

Testcase #1133.874 ms42 MB + 1008 KBAcceptedScore: 4

Testcase #1263.937 ms70 MB + 584 KBAcceptedScore: 4

Testcase #1360.906 ms65 MB + 132 KBAcceptedScore: 4

Testcase #1484.681 ms93 MB + 720 KBAcceptedScore: 4

Testcase #1595.235 ms87 MB + 812 KBAcceptedScore: 4

Testcase #16107.209 ms116 MB + 876 KBAcceptedScore: 4

Testcase #17134.808 ms110 MB + 696 KBAcceptedScore: 4

Testcase #1874.772 ms58 MB + 548 KBAcceptedScore: 4

Testcase #1987.311 ms77 MB + 572 KBAcceptedScore: 4

Testcase #20101.704 ms96 MB + 948 KBAcceptedScore: 4

Testcase #21116.021 ms116 MB + 1000 KBAcceptedScore: 4

Testcase #22119.306 ms116 MB + 824 KBAcceptedScore: 4

Testcase #23118.444 ms116 MB + 760 KBAcceptedScore: 4

Testcase #24117.411 ms116 MB + 960 KBAcceptedScore: 4

Testcase #25116.63 ms116 MB + 1008 KBAcceptedScore: 4


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