SCOI2012 喵星球上的點名

2022-09-01 11:24:13 字數 2161 閱讀 4724

我居然做出了這題……難以置信!

首先,思路很明顯是把所有串全懟一起(包括名字和詢問串),加上分隔符,然後跑一遍字尾陣列。

我們仍然可以用單調棧求出關於每個詢問串與它相同的區間。即,如果以詢問串為字首的那個字尾的\(rank\)是\(p\)的話,它的合法區間\([l,r]\)應該滿足\(\forall l。注意這裡是\(\geq\)而非\(>\),因此應該特別注意處理\(=\)的部分。

這裡放一下求出全部\([l,r)\)的**(注意這裡陣列中的\([l,r)\)實際上是左閉右開的,而我們最終要求的\([l,r]\)是左閉右閉的,所以接下來用的時候\(r\)要減去\(1\)):

for(int i=1;iht[i])r[stk[tp--]]=i;

if(ht[stk[tp]]==ht[i])l[i]=l[stk[tp]];

else l[i]=stk[tp];

stk[++tp]=i;

}while(tp)r[stk[tp--]]=n;

求出所有合法的\([l,r]\)後,我們可以考慮那兩個詢問了。

首先,對於第一問,發現它就是求區間\([l,r]\)內部所有出現過的姓名串的數量。這不就是[sdoi2009]hh的項鍊嗎?樹狀陣列即可。當然你要真想寫莫隊也沒人攔得住你。

然後,關於第二問,它的意義實際上是將區間\([l,r]\)內部所有出現過的姓名串的計數器增加\(1\)。如果關於詢問串下手我們沒有辦法,但是我們可以關於姓名串下手呀!

我們設乙個下標\(i\),它所代表的姓名串為**中的\(id\big[sa[i]\big]\),我們這裡設乙個\(c_i\)代表它。我們再設它之前上乙個出現的該姓名串的下標為\(las_i\)(如果之前沒有出現任何這個姓名串的下標,\(las_i=-1\))。則顯然,所有滿足\(i\in[l,r]\)且\(las_i的區間\([l,r]\)都可以對\(c_i\)有貢獻。這是什麼?二維數點問題呀!

於是我們愉快地排個序就能用線段樹求出答案。

複雜度\(o(n\log n)\)。

**:

#includeusing namespace std;

int s,t,cnt,id[400100],tms[400100],ans[400100],stt[400100],p,q,len[400100];

//-------------------suffix array below--------------------

int stk[400100],tp,l[400100],r[400100];

namespace suffix_array

bool cmp2(query &u,query &v)

#define lson x<<1

#define rson x<<1|1

#define mid ((l+r)>>1)

int tag[1600100];

void pushdown(int x)

void modify(int x,int l,int r,int l,int r)

while(tp)r[stk[tp--]]=n;

for(int i=1;i<=t;i++)if(ht[rk[stt[i]]]==len[i])q[++q]=query(l[rk[stt[i]]],r[rk[stt[i]]]-1,i);

// for(int i=0;is||!id[sa[j]])continue;

las[j]=las[id[sa[j]]],las[id[sa[j]]]=j;

if(las[j]!=-1)add(las[j],-1);

add(j,1);

p[++p]=make_pair(j,las[j]);

} ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1);

} for(int i=1;i<=t;i++)printf("%d\n",ans[i]);

sort(q+1,q+q+1,cmp2),sort(p+1,p+p+1,cmp);

for(int i=1,j=1;i<=p;i++)

for(int i=1;i<=s;i++)printf("%d ",tms[i]);

return 0;

}

SCOI2012 喵星球上的點名

有n個串,代表n個人的姓氏和名字,都是用很多個數字表示的,比如我姓1,2,3,4,名4,5,6,7。然後有m個點名串,如果點到了某個人的姓或名裡面的某一串,那個人就被點到,不過乙個人在乙個點名串中只能被點一次。比如點名串是2,3,4,我的姓中含有2,3,4,那麼我就會被叫到。求每個學生分別被叫到多少...

SCOI2012 喵星球上的點名

給出n個模式串,m個文字串,每個模式串由兩部分組成,我們認為乙個模式串被乙個文字串包含只要這個文字串包含它的兩部分中的其中一部分的子串。求每個文字串包含多少個模式串,每個模式串又被多少個文字串包含。1 n 20000,1 m 50000,模式串總長和文字串的總長分別不超過100000 保證模式串和文...

SCOI2012 喵星球上的點名

對於第乙個詢問,對於姓名串建廣義字尾自動機,那麼我們對於插入乙隻喵的姓名串,要將這兩個 姓和名 串的所有字串位置打標記,怎麼搞呢,其實可以直接插入暴力向上跳,複雜度的話 對於乙個串假設長度為x,那麼插入複雜度是min x x,x n 而最多只有n x個這樣的串,算一下總的複雜度上界是n根號的。然後就...