1. 程式人生 > >Bzoj4598: [Sdoi2016]模式字符串 點分治 哈希

Bzoj4598: [Sdoi2016]模式字符串 點分治 哈希

自帶 ons clu 模式 dde rom sin 時間 cas

國際慣例的題面:
技術分享圖片
這種關於樹上路徑的題,我也沒什麽好辦法,只好點分治。
考慮當前分治重心為root,如何統計經過分治重心的路徑的答案。
我們令prf[i]表示某個點到root的路徑(不含root)已經循環匹配S的前綴到位置i(下標從1開始到m-1,結尾為0)的方案數,suf[i]表示某個點到root的路徑(不含root)已經循環匹配S的後綴到位置i(下標從1開始到m-1,結尾為0)的方案數。
對於每一個點,考慮當前這個點到root的路徑(不含root)加上root作為前綴或者後綴,能和root的其他子樹組成的方案數。
那麽我們找到當前的匹配長度,讀取一下prf和suf在root的其他子樹中的前綴和就好了。(像這種維護二元組數量不算自身對自身的有一個套路,就是讓自身和前面的和去計算貢獻,這樣能保證,每組被計算且僅計算一遍)
因為我們要實現在一個串的前面追加一個字符串並查詢字符串是否相等,所以要用到哈希(因為這個相等關系不滿足單調性)。

然後就是我智障的故事了:
找重心的時候沒有重置maxsiz,導致分治被卡n^2且遞歸深度很大。
一開始在洛谷RE,八中TLE,表示很不服,然後下載了LOJ的數據。
下來測,TLE,發現找分治重心不太對。
然後造了一條鏈的數據卡他,本地Linux下RE,第一遍重心都找不到。
調系統錯誤日誌發現是崩棧,果斷ulimit -s。
然後還是直播崩棧花式崩棧崩棧到懷疑人生,用那個調日誌的root終端,發現ulimit -s出來的數值不一樣。
又開了一個終端,發現ulimit -s出來的數值還不一樣?這才發現ulimit -s僅單個終端有效!
趕緊用我開過棧的終端運行程序,不崩棧了,TLE了。這才發現找重心的問題。

(我可真是菜,這種水題都一遍寫不對)

代碼:

技術分享圖片
 1 #pragma GCC optimize(2)
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cctype>
 6 #include<iostream>
 7 #define debug cerr
 8 using namespace std;
 9 typedef unsigned long long int ulli;
10 using std::max;using std::reverse;
11 const int
maxn=1e6+1e2; 12 const ulli base = 31; 13 const int inf=0x3f3f3f3f; 14 15 char in[maxn],tar[maxn]; // input string and target string . 16 ulli pows[maxn],hpr[maxn],hsu[maxn]; // hash prefix and hash suffix . 17 int s[maxn],t[maxn<<1],nxt[maxn<<1],ban[maxn],cnt; 18 int dep[maxn],siz[maxn],mxs[maxn],prf[maxn],suf[maxn],sprf[maxn],ssuf[maxn]; //
mxs[0] = inf , paired prf[length] . 19 int n,m; 20 ulli ans; 21 22 bool vis[maxn]; 23 24 inline void addedge(int from,int to) { 25 t[++cnt] = to , nxt[cnt] = s[from] ,s[from] = cnt; 26 } 27 inline void findroot(int pos,const int &fa,const int &fs,int &rt) { 28 siz[pos] = 1 , mxs[pos] = 0; 29 for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) { 30 findroot(t[at],pos,fs,rt) , siz[pos] += siz[t[at]] , mxs[pos] = max( mxs[pos] , siz[t[at]] ); 31 } 32 if( ( mxs[pos] = max( mxs[pos] , fs - siz[pos] ) ) <= mxs[rt] ) rt = pos; 33 } 34 inline void dfs(int pos,int fa,int dep,int &mxd,const char &mid,ulli h) { 35 mxd = max( mxd , dep ) , h += in[pos] * pows[dep-1]; // add in[pos] to first char . 36 if( h == hpr[dep] ) { 37 ++prf[dep%m]; 38 if( mid == tar[dep%m+1] ) ans += ssuf[m-dep%m-1]; 39 } 40 if( h == hsu[dep] ) { 41 ++suf[dep%m]; 42 if( mid == tar[m-dep%m] ) ans += sprf[m-dep%m-1]; 43 } 44 for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) dfs(t[at],pos,dep+1,mxd,mid,h); 45 } 46 inline void solve(int pos,int fs) { 47 if( fs < m ) return; 48 int rt = 0 , full = 0; 49 *mxs = inf , findroot(pos,-1,fs,rt) , ban[rt] = 1; 50 if( in[rt] == tar[1] ) ++sprf[0]; 51 if( in[rt] == tar[m] ) ++ssuf[0]; 52 for(int at=s[rt],mxd;at;at=nxt[at]) if( !ban[t[at]] ) { 53 mxd = 0 , dfs(t[at],rt,1,mxd,in[rt],0) , full = max( full , mxd ); 54 for(int i=0;i<=mxd;i++) sprf[i] += prf[i] , ssuf[i] += suf[i] , prf[i] = suf[i] = 0; 55 } 56 for(int i=0;i<=full;i++) sprf[i] = ssuf[i] = 0; 57 for(int at=s[rt];at;at=nxt[at]) if( !ban[t[at]] ) solve(t[at],siz[t[at]]<siz[rt]?siz[t[at]]:fs-siz[rt]); 58 } 59 60 inline char nextchar() { 61 static const int BS = 1 << 21; 62 static char buf[BS],*st=buf+BS,*ed=buf+BS; 63 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 64 return st == ed ? -1 : *st++; 65 } 66 inline int getint() { 67 int ret = 0 , ch; 68 while( !isdigit(ch=nextchar()) ); 69 do ret = ret * 10 + ch - 0; while( isdigit(ch=nextchar()) ); 70 return ret; 71 } 72 inline void getstr(char* s) { 73 char ch; 74 while( !isalpha(ch=nextchar()) ); 75 do *s++ = ch; while( isalpha(ch=nextchar()) ); 76 } 77 inline void gethsh(ulli* dst) { 78 for(int i=m+1;i<=n;i++) tar[i] = tar[i-m]; 79 for(int i=1;i<=n;i++) dst[i] = dst[i-1] * base + tar[i]; 80 } 81 inline void fix(char* s,int len) { 82 for(int i=1;i<=len;i++) s[i] -= A - 1; 83 } 84 inline void solve_case() { 85 n = getint() , m = getint() , getstr(in+1) , fix(in,n) , memset(s,0,sizeof(s)) , memset(ban,0,sizeof(ban)) , cnt = ans = 0 , *pows = 1; 86 for(int i=1;i<=n;i++) pows[i] = pows[i-1] * base; 87 for(int i=1,a,b;i<n;i++) a = getint() , b = getint() , addedge(a,b) , addedge(b,a); 88 getstr(tar+1) , fix(tar,m) , gethsh(hpr) , reverse(tar+1,tar+1+m) , gethsh(hsu) , reverse(tar+1,tar+1+m); 89 solve(1,n) , printf("%llu\n",ans); 90 } 91 92 int main() { 93 static int T; 94 T = getint(); 95 while(T--) solve_case(); 96 return 0; 97 }
View Code


話說我自帶大常數的代碼竟然跑到了第一頁?
技術分享圖片

変わらない毎日めぐりめぐる
不變的每日一天又一天
何も無い時間が過ぎる
流逝著無所事事的時間

風にゆらめいて歩き出せば
如果在風中飄舞著邁出步伐
いつか変わるかな? 明日
明天總會有所改變的吧?

無くしたものを 探しては あきらめて
已逝之物 探尋又放棄
一人佇み 空を見ていた
就這麽一個人站著 看著天空

Bzoj4598: [Sdoi2016]模式字符串 點分治 哈希