1. 程式人生 > >bzoj千題計劃317:bzoj4650: [Noi2016]優秀的拆分(字尾陣列+差分)

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

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

#define N 30002

using namespace std;

int n;
char s[N];

int pre[N],suf[N];

int Log[N];

struct SA
{
    int a[N];
    int sa[2][N],rk[2][N];
    int v[N];
    int p,q;
    int k;
    
int height[N]; int st[N][15]; 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 pre_sa() { p=0; q=1; memset(v,0,sizeof(v)); memset(rk,0,sizeof(rk)); 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 pre_height() { int j,k=0; 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 pre_st() { memset(st,0,sizeof(st)); for(int i=2;i<=n;++i) st[i][0]=height[i]; for(int j=1,k=1;j<=14;++j,k<<=1) for(int i=2;i+k*2-1<=n;++i) st[i][j]=min(st[i][j-1],st[i+k][j-1]); } void pre() { pre_sa(); pre_height(); pre_st(); } int get(int i,int j) { i=rk[p][i]; j=rk[p][j]; if(i>j) swap(i,j); i++; int l=Log[j-i+1]; return min(st[i][l],st[j-(1<<l)+1][l]); } }; SA SA1,SA2; void solve() { memset(pre,0,sizeof(pre)); memset(suf,0,sizeof(suf)); int j; int lcp,lcs; int cnt=0; for(int len=1;len<n;++len) { for(int i=len;i+len<=n;i+=len) { j=i+len; lcp=SA1.get(i,j); if(lcp>len) lcp=len; lcs=SA2.get(n-i+1,n-j+1); if(lcs>len) lcs=len; if(lcp+lcs-1>=len) { suf[j+len-lcs]++; suf[j+lcp]--; pre[i-lcs+1]++; pre[i+lcp-len+1]--; } } } for(int i=2;i<=n;++i) pre[i]+=pre[i-1],suf[i]+=suf[i-1]; long long ans=0; for(int i=2;i<=n-2;++i) ans+=1LL*suf[i]*pre[i+1]; cout<<ans<<'\n'; } int main() { //freopen("testdata.in","r",stdin); //freopen("__.txt","w",stdout); int T; scanf("%d",&T); for(int i=2;i<N;++i) Log[i]=Log[i>>1]+1; while(T--) { scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i) SA1.a[i]=s[i]-'a'+1; memcpy(SA2.a,SA1.a,sizeof(SA2.a)); reverse(SA2.a+1,SA2.a+n+1); SA1.a[n+1]=SA2.a[n+1]=0; SA1.pre(); SA2.pre(); solve(); } }

相關推薦

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

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

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

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

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

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

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

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

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計劃323bzoj1951: [Sdoi2010]古代豬文Lucas+CRT+尤拉定理

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

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

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

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計劃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 4326 運輸計劃LCA +樹上

任重而道遠 Description 公元 2044 年,人類進入了宇宙紀元。L 國有 n 個星球,還有 n?1 條雙向航道,每條航道建立在兩個星球之間, 這 n-1 條航道連通了 L 國的所有星球。小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如 :有一艘物流飛船

BZOJ 4698: Sdoi2008 Sandy的卡片(字尾陣列++二分答案)

傳送門 解題思路   看到一個子串加一個數字到另一個子串,自然可以想到差分。然後要把所有串都拼起來,求出\(height\)陣列後可以二分答案來做,每次二分一個答案後統計一下連續的\(height>=\)二分出答案的段是否將每個串都涵蓋。 程式碼 #include<iostream>

BZOJ4650 : [NOI2016]優秀拆分

down amp while 個數 code getch span str size 題面 傳送門 Sol 求個以\(i\)為結尾的\(AA\)串的個數和以\(i\)為開頭的\(AA\)串的個數 乘法原理即可,暴力求有95分 而你會發現,枚舉l,經過\(i\)和\(i+l\