1. 程式人生 > >bzoj千題計劃313:bzoj3879: SvT(字尾陣列+st表+單調棧)

bzoj千題計劃313:bzoj3879: SvT(字尾陣列+st表+單調棧)

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 500001
#define M 3000001

int n,m,mm;
char s[N];
int a[N];

int b[M],r[N];

int v[N];
int p,q=1,k;
int sa[2][N],rk[2][N];

int height[N],h[N];
int st[N][16];

int Log[N];

int ST[N],top;
int num[N],val[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void mul(int *sa,int *rk,int *SA,int *RK) { for(int i=1;i<=n;++i) v[rk[sa[i]]]=i; for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i; for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]] || rk[SA[i]+k]!=rk[SA[i-1]+k]); } void presa() { for(int i=1;i<=n;++i) v[a[i]]++; for(int i=1;i<=26;++i) v[i]+=v[i-1]; for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;
for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]); for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); } void get_height() { int k=0,j; for(int i=1;i<=n;++i) { j=sa[p][rk[p][i]-1]; while(a[i+k]==a[j+k]) k++; height[rk[p][i]]=k; if(k) k--; } } void prest() { for(int i=2;i<=n;++i) st[i][0]=height[i]; for(int i=1,k=2;i<=15;++i,k<<=1) for(int j=2;j+k-1<=n;++j) st[j][i]=min(st[j][i-1],st[j+k/2][i-1]); } int get(int i,int j) { i++; int l=Log[j-i+1]; return min(st[i][l],st[j-(1<<l)+1][l]); } void solve() { for(int i=1;i<=mm;++i) r[i]=rk[p][b[i]]; sort(r+1,r+mm+1); for(int i=2;i<=mm;++i) h[i]=get(r[i-1],r[i]); top=0; int tmp_num; long long now=0,ans=0; for(int i=2;i<=mm;++i) { tmp_num=0; while(top && h[i]<=h[ST[top]]) { now-=1LL*num[top]*val[top]; tmp_num+=num[top--]; } tmp_num++; ST[++top]=i; num[top]=tmp_num; val[top]=h[i]; now+=1LL*tmp_num*h[i]; ans+=now; } cout<<ans<<'\n'; } int main() { int T; read(n); read(T); for(int i=2;i<=n;++i) Log[i]=Log[i>>1]+1; scanf("%s",s+1); for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1; presa(); get_height(); prest(); while(T--) { read(m); for(int i=1;i<=m;++i) read(b[i]); sort(b+1,b+m+1); mm=unique(b+1,b+m+1)-b-1; solve(); } }

相關推薦

bzoj計劃313bzoj3879: SvT字尾陣列+st+單調

#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 500001 #define M 3000001 int n,m,mm;

bzoj計劃314bzoj3238: [Ahoi2013]差異字尾陣列+st+單調

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 500001 int n

bzoj計劃311bzoj5017: [Snoi2017]炸彈線段樹優化tarjan構圖

#include<cstdio> #include<vector> #include<iostream> #include<algorithm> using namespace std; const int mod=1e9+7;

bzoj計劃319bzoj2865: 字串識別字尾自動機 + 線段樹

#include<map> #include<cstdio> #include<cstring> #include<algorithm> #define N 500001 using namespace std; char s[

bzoj計劃310bzoj5285: [Hnoi2018]尋寶遊戲(思維+雜湊)

#include<cstdio> #include<algorithm> #define N 5001 using namespace std; const int mod=1e9+7; int bit[N]; char s[N]; int has

bzoj計劃316bzoj3173: [Tjoi2013]最長上升子序列二分+樹狀陣列

#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 #define lowbit(x) x&-x

bzoj計劃309bzoj4332: JSOI2012 分零食分治+FFT

#include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int M=1<<17; #define N 10001 int m,

bzoj計劃321bzoj5251: [2018多省省隊聯測]劈配網路流 + 二分

#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #d

bzoj計劃312bzoj2119: 股市的預測字尾陣列+st

#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #d

bzoj計劃317bzoj4650: [Noi2016]優秀的拆分字尾陣列+差分

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 30002 using namespace std; int n;

bzoj計劃318bzoj1396: 識別子串字尾自動機 + 線段樹

#include<cstdio> #include<cstring> #include<algorithm> #define N 100001 using namespace std; char s[N]; int ch[N<&

bzoj計劃323bzoj1951: [Sdoi2010]古代豬文Lucas+CRT+尤拉定理

#include<cmath> #include<cstdio> #include<iostream> using namespace std; const int mod=999911659; const int phi=mod-1; typ

bzoj計劃322bzoj2561: 最小生成樹最小割

#include<cstdio> #include<queue> #include<cstring> #include<iostream> #include<algorithm> using namespace std;

bzoj計劃324bzoj5249: [2018多省省隊聯測]IIIDX線段樹

#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 500001 int d[N

bzoj計劃320bzoj4939: [Ynoi2016]掉進兔子洞莫隊 + bitset

#include<cmath> #include<cstdio> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> us

bzoj計劃308bzoj4589: Hard Nim倍增FWT+生成函式

#include<cstdio> #include<cstring> using namespace std; #define N 50001 const int mod=1e9+7; const int M=1<<16; int inv

bzoj計劃315bzoj3172: [Tjoi2013]單詞AC自動機

#include<queue> #include<cstdio> #include<cstring> using namespace std; #define N 2000001 using namespace std; int pos[20

BZOJ 4453 cys就是要拿英魂!字尾陣列+單調+平衡樹

一開始的時候感覺就是一個主席書裸題。 然後發現自己錯了。 首先建出字尾陣列。 設\(i<j\) 如果\(rk[i]>rk[j]\)顯然i更優。 如果\(rk[i]<rk[j]\)不一定是j更優。 當\(i+lcp(i,j)-1<=j\)時是\(j\)優,否則\(i\)更優。 所以我們有

BZOJ[4516][Sdoi2016]生成魔咒 字尾陣列+ST+線段樹

首先感謝Sinogi大佬的耐心講解及程式碼 題意就是每次加一個字元,統計本質不同的子串數量 正向新增字元不好做,考慮反著刪字元 在正常情況下,刪掉位置ii的一個字元會減少ii個子串(∑j<=ij=1sj...i∑j=1j<=isj...i)

LeetCode刷筆記-009palindrome number迴文數

題目描述: Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward. Exa