cdoj 1485 柱爺搞子串 sam treap

2022-02-07 06:22:17 字數 3274 閱讀 5400

(

柱爺有乙個字串s,對於其中的每乙個不同子串\(s^\ast\),柱爺都能o(1)

的得到這些字串的所有匹配位置

即能知道所有的[l,r]

區間使得 \(s[l,r]=s^\ast\),然後柱爺會把這些[l,r]區間的每個位置做上標記,如果最後這些標記位置形成了k個連通塊,那麼它對答案的貢獻就是1

柱爺早就知道了答案,但他現在想問你知道嗎?

輸入第一行乙個字串s,只有小寫字母,保證\(|s|≤10^5\)

接下來一行乙個k

,保證\(1≤k≤|s|\)

輸出一行表示答案

abaab

2對於ababa的字串aba它對所有字元都打上了標記,所以只有1個聯通塊

對於每乙個不同字串,對他的每乙個出現位置的每乙個字元都打上標記,形成k個聯通塊答案加1。

換個角度,如果我們知道了sam字尾自動機裡面每個節點的right集,對於每乙個right集,我們就可以知道乙個字串長度區間使這個集合形成k個聯通塊,再和這個節點的接受長度區間取個交就是這個節點的所有可行解。

串長度有1e5,對於全是a資料,他的right集和的個數達到1e10,顯然暴力出right集是不行的。

那麼我們可以用set的維護right集,用平衡樹維護right的差分陣列,維護出來後對於差分陣列我們只要求第size-k的大小就可以算得貢獻。最後用啟發式合併一下,雖然總體是nloglog,但在字尾樹上的啟發式跑得很快。

如果是隨機資料,那麼直接用set爆出right集應該也是沒有問題的。

//#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;

long double esp=1e-11;

//#pragma comment(linker, "/stack:1024000000,1024000000")

#define fi first

#define se second

#define all(a) (a).begin(),(a).end()

#define cle(a) while(!a.empty())a.pop()

#define mem(p,c) memset(p,c,sizeof(p))

#define mp(a, b) make_pair(a, b)

#define pb push_back

#define lson l , m , rt << 1

#define rson m + 1 , r , rt << 1 | 1

typedef long long int ll;

const long double pi = acos((long double)-1);

const ll inf=0x3f3f3f3fll;

const int mod =1000000007ll;

const int maxn=100100;

int cnt,rot[maxn<<1]; //可重複,s表示節點的值的個數

struct treaptr[maxn*50];

inline void updata(int a)

inline int newtreap(int _val)

void init()

int merge(int a,int b)else

return y;

}int findkth(int t,int k)

void delete(int k,int t)

void pr(int t)

#define len 101000

#define alp 26

int pa[len<<1],son[len<<1][alp],right[len<<1];

int max[len<<1],cnt,root,last; //0為null節點,null只能到null

inline int newnode(int _max)

inline void pre()

inline void sam(int alp,int t) //注意t=26,s[x]-'a',多串時每次last=root

//已有狀態,對所有父狀態更新

else np=newnode(max[last]+1);

right[np]=t;

while(u&&!son[u][alp])son[u][alp]=np,u=pa[u];

if(!u)pa[np]=root;

else

}last=np;

}char s[maxn];

int k;

ll ans=0;

vectornode[maxn<<1];

setq[maxn<<1];

set::iterator iter,it;

int pos[maxn<<1],cc=0;

void ins(int val,int t)

else

q[pos[t]].insert(val);

}void dfs(int u)

//printf("\nnode%d %d\n",u,mapos);

rot[u]=rot[mapos];

if(mapos)pos[u]=pos[mapos];

else pos[u]=cc++,q[pos[u]].clear(),q[pos[u]].insert(-maxn*2);

if(right[u])ins(right[u],u);

for(int x:node[u])

if(x!=mapos)

if(tr[rot[u]].size>=k)

}// printf("%d %d %d\n",u,pa[u],right[u]);

// for(int val:q[pos[u]])printf("%d ",val);puts("");

// pr(rot[u]);puts("");

//答案

}void test()

for(int x=0;x<=cnt;x++)

node[x].clear();

init();

for(int x=1;x<=cnt;x++)

if(pa[x])

node[pa[x]].pb(x);

dfs(1);

}int main()

CDOJ1357 柱爺與最大區間和

傳送門 分析 首先,我們需要知道怎麼求一段最大區間和。從左往右掃的時候,用pre記錄當前的最大值,f i 表示從最左端到i這個區間上的最大和。當掃到i時,如果pre已經小於0,那麼直接將a i 賦值給pre,否則加上a i 然後f i max f i 1 pre 時間複雜度為o n 求兩段的話,再倒...

CDOJ 2016 B 柱爺與最大區間和

柱爺愛思考,凡事喜歡舉一反三,常常能想到別人沒想過的問題。比如最大區間和這個問題 在一數列上選出一段區間,使得這段區間和最大。柱爺想 如果選出兩段區間 不相鄰 會怎樣呢?柱爺很快想到了答案,你呢?input 第一行輸入乙個數n,表示陣列的長度。第二行輸入n個數,表示各元素的值。資料保證 3 n 50...

CDOJ 1401 譚爺的黑暗沙拉 數學

譚爺有 n 種不同種類的食材 水果 蔬菜 他想做出乙份總重量為 k 的黑暗沙拉。他想讓機智的你告訴他,他能做多少種不同的黑暗沙拉!說明 1.可以重複選擇食材,而且不需要選完全部的 n 種食材,但是最後總重量必須是 k 2.兩份沙拉不同,當且僅當 k 重量食材的種類或配比不同。3.每種食材只能選擇非負...