NOI2016 優秀的拆分

2022-03-26 19:00:37 字數 1653 閱讀 3272

題目

好像經典的做法是關鍵點+調和級數,但是不太會;於是就打個sam+暴力啟發式合併

我們只需要算一下每個\(i\)是多少個aa串的結尾,是多少個bb串的開頭,我們發現這兩個問題其實是等價的;我們算每個\(i\)是多少個aa串的結尾即可;

其實我們只需要對於每個\(i\)算有多少\(j滿足\(i-j\leq(i,j)\)即可;

大力啟發式合併,考慮把小集合合併到大集合上產生的影響,發現非常好考慮,就是乙個區間加和乙個區間查,線段樹就好了;

複雜度\(o(n\log^2n)\),**

#include#define re register

#define ll long long

const int maxn=6e4+5;

const int m=maxn*20;

char s[maxn>>1];

int len[maxn],son[maxn][26],fa[maxn];

int tax[maxn>>1],a[maxn],n,lst,cnt,tot,tmp;

int a[maxn>>1],b[maxn>>1],ans[maxn>>1],g[maxn>>1];

int l[m],r[m],d[m],tag[m],rt[maxn],pos[maxn>>1];

inline void ins(int c) int x=son[f][c];

if(len[f]+1==len[x])

int y=++cnt;len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;

for(re int i=0;i<26;i++)son[y][i]=son[x][i];

while(f&&son[f][c]==x)son[f][c]=y,f=fa[f];

}inline int newnode()

int chg(int nw,int x,int y,int pos)

void add(int nw,int x,int y,int lx,int ry) int mid=x+y>>1;

if(lx<=mid)add(l[nw],x,mid,lx,ry);if(ry>mid)add(r[nw],mid+1,y,lx,ry);

}void dfs(int nw,int x,int y,int v)

int mid=x+y>>1;dfs(l[nw],x,mid,v);dfs(r[nw],mid+1,y,v);

}int mof(int nw,int x,int y,int pos,int v) int mid=x+y>>1;

(pos<=mid?l[nw]=mof(l[nw],x,mid,pos,v):r[nw]=mof(r[nw],mid+1,y,pos,v));return nw;

}int ask(int nw,int x,int y,int lx,int ry)

inline void main()

for(re int j=1;j<=tmp;j++) rt[f]=mof(rt[f],1,n,a[j],b[j]);

} tmp=0;dfs(rt[1],1,n,0);

for(re int i=1;i<=tmp;i++)ans[a[i]]=b[i];

}int main()

return 0;

}

NOI2016 優秀的拆分

看到題目,資料範圍有點怪異。對於95 的資料,對於100 的資料,意思是只有5分是正解。好吧,95pts的 很明顯,答案就是 而如何才能拿到100pts呢?我們可以先列舉a段的長度,很明顯每個長度為lcp,與往後求lcs,若 這樣就可以通過 include include include inclu...

NOI2016 優秀的拆分

題目實際上要求我們求從每個點出發的aa串的數量 考慮點i的答案,發現如果字首i與字首j j i 的最長公共字尾 i j,那麼i點出發向前就存在乙個長度為i j的aa串,題目即求對於每個字首,有多少個在他之前的字首滿足條件 考慮字尾自動機,由於每個字首都是字尾自動機parent樹上的一點,即兩個字首的...

NOI2016 優秀的拆分

點此看題 首先轉化問題,我們可以求出a i b i a i b i a i b i 即以i ii結束 開始的aaaa aa串的數量,這樣答案就可以表示為 a i b i 1 sum a i times b i 1 a i b i 1 求這兩個陣列,可以隔距離len lenle n設定乙個點,這樣乙個...