字符串作業(三)

LOJ #6158. A + B Problem

給出一個數字,求在其中兩位之間插入一個加號後得到的答案末尾00最多的個數。

題解:
第二個數的末尾就是原串的末尾,所以如果需要和第一個數加起來末尾爲00,那麼從後往前掃,第二個數爲00的位在不進位的情況下第一個數的對應位需要是00,不爲00的位的對應位xx應該是10x10 - x,然後開啓進位模式所有數的對應位都是9x9-x,然後求一個原串和轉換後的串的最長公共前綴即可得出答案,可以寫exkmp\rm exkmp
AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 1000006
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define mod 998244353
#define S 131
#define LL long long
using namespace std;

char s[maxn],s0[maxn];
LL hs[2][maxn],pw[maxn];
int n;

LL calc(int a,int b,LL *hs){ return ((hs[b] - hs[a-1] * pw[b-a+1]) % mod + mod) % mod; }

int main(){
	pw[0] = 1;
	rep(i,1,maxn-1) pw[i] = pw[i-1] * S % mod;
	while(scanf("%s",s+1)!=EOF){
		n = strlen(s+1);
		rep(i,1,n) hs[0][i] = (hs[0][i-1] * S + s[i]) % mod , s0[i] = s[i]; 
		int i;
		for(i=n;i>=1 && s[i] == '0';i--);
		s[i] = (10 - (s[i] - '0')) + '0';
		int t = i;
		per(j,i-1,1) s[j] = (9 - (s[j] - '0')) + '0';
		rep(i,1,n) hs[1][i] = (hs[1][i-1] * S + s[i]) % mod;
		int ans = 0;
		rep(i,1,n-1){
			int L = 0 , R = min(i , n-i) , mid;
			for(;L<R;){
				mid = L+R+1 >> 1;
				if(calc(i-mid+1,i,hs[0]) == calc(n-mid+1,n,hs[1]))
					L = mid;
				else 
					R = mid - 1;
			}
			if(i <= t){
				while(n-L <= i && s0[i-L] == '9') L++;
				while(i-L <= 0 && n-L > i && s0[n-L] == '9') L++;
			}
			else{
				while(n-L <= i && s0[i-L] == '0') L++;
				while(i-L <= 0 && n-L > i &&s0[n-L] == '0') L++;
			}
			ans = max(ans , L);
		}
		printf("%d\n",ans);
	}
}

CF914F Substrings in a String

題意:單點修改SS中的一個字符,求S[l...r]S[l...r]TT的出現次數,S,T1e5Timelimit 6s|S| , \sum|T| \leq 1e5,\rm Timelimit \ 6s

太離譜了。
考慮到這是CF\rm CF6s\rm 6s,我們用bitset C[i][j]\rm bitset\ C[i][j]代表字符ii在位置jj是否出現。
則求出ret=andi=0T1C[Ti]>>iret = \operatorname{and}_{i=0}^{|T|-1} C[T_i]>>i後取retret[l,rT+1][l,r-|T|+1]中的11的個數即可。
時間複雜度O(n2ω)O(\frac {n^2}{\omega})無壓力水過
其實可以分塊一下得到更科學的複雜度:
對於長度大於塊大小SS的字符串我們暴力kmp\rm kmp,O(n2S)O(\frac {n^2}S)
對於長度小於塊大小SS的字符串我們分它是在一個塊內還是跨兩個塊來考慮。
對於塊內的答案直接分塊求塊內的bitset\rm bitset即可做到O(nSω)O(\frac {nS}{\omega})
對於跨兩個塊的答案直接對於nS\frac nS個交界處前後T|T|個字符拿出來跑kmp\rm kmpO(nTS)O(\frac {n|T|}S),總複雜度還是O(n2S)O(\frac {n^2}S)
所以S=ωnS = \sqrt {\omega n}時最快,爲O(nnω)O(\frac {n\sqrt n}{\sqrt \omega})

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 100005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
using namespace std;

char s[maxn],ch[maxn];
int Q,n;

bitset<maxn>C[26];

int main(){
	scanf("%s",s+1);
	n = strlen(s+1);
	rep(i,1,n) C[s[i] - 'a'][i] = 1;
	scanf("%d",&Q);
	for(int op,l,r;Q--;){
		scanf("%d%d",&op,&l);
		if(op == 1){
			scanf("%s",ch);
			C[s[l]-'a'][l] = 0;
			C[(s[l]=ch[0])-'a'][l] = 1;
		}
		else{
			scanf("%d%s",&r,ch);
			int t = strlen(ch);
			static bitset<maxn>ans;
			ans.set();
			rep(i,0,t-1)
				ans &= (C[ch[i] - 'a'] >> i);
			r -= t - 1;
			ans <<= maxn - 1 - r;
			ans >>= maxn - 1 - r + l;
			printf("%d\n",ans.count());
		}
	}
}

O(nnw)O(\frac {n\sqrt n}{\sqrt w})做法:(實際上沒有快多少)

#include<bits/stdc++.h>
#define maxn 100005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
#define S 1800
using namespace std;

char s[maxn],ch[maxn];
int Q,n,id[maxn],st[maxn],ed[maxn],nxt[maxn],m;

bitset<S>C[26][maxn/S+5];

int kmp(int l,int r){
	int ans = 0;
	for(int i=l,j=0;i<=r;i++){
		while(j != -1 && ch[j] != s[i]) j = nxt[j];
		if(++j == m) ans ++;
	}
	return ans;
}

int solve(int b,int l,int r){
	static bitset<S>ans;ans.set();
	rep(i,0,m-1) ans &= C[ch[i]-'a'][b] >> i;
	r -= m - 1;
	ans <<= S - 1 - r;
	ans >>= S - 1 - r + l;
	return ans.count();
}

int main(){
	scanf("%s",s+1);
	n = strlen(s+1);
	rep(i,1,n) id[i] = i / S , st[id[i]] = st[id[i]] ? st[id[i]] : i , ed[id[i]] = i;
	rep(i,1,n) C[s[i]-'a'][id[i]][i - st[id[i]]] = 1;
	scanf("%d",&Q);
	for(int op,l,r;Q--;){
		scanf("%d%d",&op,&l);
		if(op == 1){
			scanf("%s",ch);
			C[s[l]-'a'][id[l]][l - st[id[l]]] = 0;
			C[(s[l]=ch[0])-'a'][id[l]][l - st[id[l]]] = 1;
		}
		else{
			scanf("%d%s",&r,ch);
			m = strlen(ch);
			nxt[0] = -1;
			for(int j=-1,k=0;k<m;)
				if(j == -1 || ch[j] == ch[k]) nxt[++k] = ++j;
				else j = nxt[j];
			int ans = 0;
			if(m >= S) ans = kmp(l,r);
			else{
				rep(i,id[l],id[r]) ans += solve(i,max(l-st[i],0),min(r-st[i],ed[i]-st[i]));
				rep(i,id[l],id[r]-1) ans += kmp(max(l,ed[i]-m+2),min(ed[i]+m-1,r));
			}
			printf("%d\n",ans);
		}
	}
}

UPD:完全錯了,後一種做法還是O(n2ω)O(\frac {n^2}{\omega})的,根號做法還是推薦分塊維護後綴自動機加kmp\rm kmp

CF1131E String Multiplication

在這裏插入圖片描述
在加入tt的時候隨便維護一下每個字母的最長相同字母連續子序列即可。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 1000006
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
using namespace std;

char s[maxn];
int n,m;
LL f[26];

int main(){
	scanf("%d",&n);
	for(;n--;){
		scanf("%s",s);
		m = strlen(s);
		vector<pair<int,int> >G;
		for(int i=0,j;i<m;i=j){
			for(j=i;j < m && s[i] == s[j];j++);
			G.push_back(make_pair(s[i]-'a' , j-i));
		}
		if(G.size() == 1){
			rep(i,0,25) if(i ^ G[0].first) 
				f[i] = min(f[i] , 1ll);
			f[G[0].first] = min(f[G[0].first] + (f[G[0].first] + 1ll) * G[0].second , (LL)1e11);
		}
		else{
			rep(i,0,25) f[i] = min(f[i] , 1ll);
			if(G[0].first == G.back().first) f[G[0].first] += G[0].second + G.back().second;
			else{
				f[G[0].first] += G[0].second;
				f[G.back().first] += G.back().second;
			} 
			rep(i,0,G.size()-1) f[G[i].first] = max(f[G[i].first] , G[i].second * 1ll);
		} 
	}
	LL ans = 0;
	rep(i,0,25) ans = max(ans , f[i]);
	printf("%d\n",ans);
}

CF653F Paper task

給定一個長度爲nn的括號串,問有多少種不同的合法的本質不同的括號子串。

一邊插入字符建出SAMSAM,一邊對於新出現的節點套個mapmap統計新節點所代表的串中有幾個合法的括號串。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 500005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long 
using namespace std;

int n;
char s[maxn];
map<int,int>P[maxn];
int fa[maxn<<1],last,len[maxn<<1],tr[maxn<<1][2],tot;
void ins(int c){
	int u = ++tot , p = last , q;
	len[last = u] = len[p] + 1;
	for(;p!=-1 && !tr[p][c];p=fa[p]) tr[p][c] = u;
	if(p == -1) fa[u] = 0;
	else if(len[q = tr[p][c]] == len[p] + 1) fa[u] = q;
	else{
		int v = ++tot;
		memcpy(tr[v],tr[q],sizeof tr[q]),fa[v]=fa[q],len[v]=len[p]+1;
		for(;p!=-1 && tr[p][c] == q;p=fa[p]) tr[p][c] = v;
		fa[q] = fa[u] = v;
	}
}

int main(){
	scanf("%d%s",&n,s+1);
	rep(i,0,n) P[i][0] = 0;
	stack<int>sta;
	LL ans = 0;fa[0] = -1;
	rep(i,1,n){
		ins(s[i] == '(' ? 0 : 1);
		if(s[i] == '(')
			sta.push(i);
		else{
			if(sta.empty()) P[0].clear(),P[0][0] = 0;
			else{
				int u = sta.top() , pr;
				sta.pop();
				if(sta.empty()) pr = 0;
				else pr = sta.top();
				int t = (*P[pr].rbegin()).second + 1;
				P[pr][u] = t;
				map<int,int>::iterator it = P[pr].lower_bound(i - len[fa[last]] + 1);
				it--;
				ans += (*it).second;
			}
		}
	}
	printf("%lld\n",ans);
} 

CF610E Alphabet Permutations

字符集爲前kk個小寫字母,給出一個長度爲n200000n \leq 200000的字符串SS,有Q20000Q \leq 20000次操作,有兩種操作,一種是將S[l,r]S[l,r]賦值爲字符cc,一種是給出kk個小寫字母的一個排列作爲字符串TT,詢問往SS中插入字符後成爲TT循環pp次後,求最小的pp

水題,線段樹隨便維護一下連續兩個字符爲abab的方案數,那麼對於給出的排列,aa的位置>>bb的位置則答案增加abab的方案數。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 200005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long 
#define lc u<<1
#define rc lc|1
using namespace std;

int n,m,K;
int tr[maxn<<2][10][10],tag[maxn<<2],len[maxn<<2],pl[maxn<<2],pr[maxn<<2];
char ch[maxn],s[maxn];

void dtp(int u,int p){
	memset(tr[u],0,sizeof tr[u]);
	tr[u][p][p] = len[u]-1;
	pl[u] = pr[u] = p;
	tag[u] = p;
}

void dt(int u){
	if(tag[u] != -1){
		dtp(lc,tag[u]);
		dtp(rc,tag[u]);
		tag[u] = -1;
 	}
}

void upd(int u){
	rep(i,0,K-1) rep(j,0,K-1) tr[u][i][j] = tr[lc][i][j] + tr[rc][i][j];
	tr[u][pr[lc]][pl[rc]] ++;
	pl[u] = pl[lc] , pr[u] = pr[rc];
}

void Build(int u,int l,int r){
	len[u] = r-l+1;
	if(l==r) return (void)(pl[u]=pr[u]=s[l]-'a');
	int m=l+r>>1;
	Build(lc,l,m),Build(rc,m+1,r);
	upd(u);
}

void ins(int u,int l,int r,int ql,int qr,int p){
	if(l>qr||ql>r) return ;
	if(ql<=l&&r<=qr) return (void)(dtp(u,p));
	int m=l+r>>1;dt(u);
	ins(lc,l,m,ql,qr,p) , ins(rc,m+1,r,ql,qr,p);
	upd(u);
}

int main(){
	memset(tag,-1,sizeof tag);
	scanf("%d%d%d",&n,&m,&K);
	scanf("%s",s+1);
	Build(1,1,n);
	for(int op,l,r,c;m--;){
		scanf("%d",&op);
		if(op == 1){
			scanf("%d%d%s",&l,&r,&ch);
			ins(1,1,n,l,r,ch[0]-'a');
		}
		else{
			scanf("%s",ch);
			static int p[11]={};
			int ans = 1;
			rep(i,0,K-1) rep(j,0,i)
				ans += tr[1][ch[i]-'a'][ch[j]-'a'];
			printf("%d\n",ans);
		}
	}
} 

CF741E Arpa’s abnormal DNA and Mehrdad’s deep interest

在這裏插入圖片描述

hashhash實現O(nlog2n)O(n\log^2n)後綴排序後就是一個求lir,x(imodk)yl\leq i \leq r , x \leq (i \bmod k) \leq yrmqrmq問題。
對於這modk\bmod k
我們分kSk \leq S,則離線後處理kk相等的所有詢問,對於imodki \bmod k相同的所有ii寫一個RMQRMQ
總複雜度O(Snlogn)O(Sn\log n)
k>Sk \gt S,則暴力找所有的x+jkiy+jkx+jk \leq i \leq y + jk的區間,複雜度O(n2S)O(\frac {n^2}S)

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 100005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
#define pb push_back
#define Ct const
#define mod 998244353
using namespace std;

char s[maxn],t[maxn];
int q,ls,lt,c[maxn],rk[maxn];
LL pw[maxn],hst[maxn],hs[maxn];

LL calc(int u,int l){
	if(l <= u) return hs[l];
	if(l <= u + lt) return (hs[u] * pw[l-u] + hst[l-u]) % mod;
	return ((hs[u] * pw[l-u] + hst[lt] * pw[l-u-lt] + hs[l-lt] - hs[u] * pw[l-lt-u]) % mod + mod) % mod;
}

int getc(int u,int l){
	if(l <= u) return s[l];
	if(l <= u + lt) return t[l-u];
	return s[l-lt];
}

bool cmp(Ct int &u,Ct int &v){
	int L = 0 , R = ls + lt , mid;
	for(;L<R;){
		mid = L+R+1 >> 1;
		if(calc(u,mid) == calc(v,mid)) L = mid;
		else R = mid - 1;
	}
	return getc(u,L+1) < getc(v,L+1);
}

#define vc vector
#define vi vector<int>
#define lim 17
#define S 100

int L[maxn],R[maxn],K[maxn],X[maxn],Y[maxn],lg[maxn],ans[maxn];
vi G[maxn];

vc<vi>st;

bool cmp2(Ct int &u,Ct int &v){ if(rk[u] < rk[v] || (rk[u] == rk[v] && u < v)) return 1;return 0; }
int qry(int u,int v){
	if(u > v) return ls+1;
	int t = lg[v-u+1];
	return cmp2(st[t][u],st[t][v-(1<<t)+1]) ? st[t][u] : st[t][v-(1<<t)+1];
}

int main(){
	scanf("%s%s%d",s+1,t+1,&q);
	ls = strlen(s+1);
	lt = strlen(t+1);
	rep(i,1,ls) hs[i] = (hs[i-1] * S + s[i]) % mod;
	rep(i,1,lt) hst[i] = (hst[i-1] * S + t[i]) % mod;
	pw[0] = 1;
	rep(i,1,ls+lt) pw[i] = pw[i-1] * S % mod; 
	rep(i,0,ls) c[i] = i;
	sort(c,c+ls+1,cmp);
	int cnt = 0;
	rep(i,0,ls)
		if(i == 0 || cmp(c[i-1],c[i]))
			rk[c[i]] = ++cnt;
		else rk[c[i]] = cnt;
	st=vc<vi>(lim,vi(ls+1));
	rep(i,0,ls) st[0][i] = i;
	rep(j,1,lim-1) rep(i,0,ls-(1<<j)+1)
		st[j][i] = cmp2(st[j-1][i],st[j-1][i+(1<<j-1)]) ? st[j-1][i] : st[j-1][i+(1<<j-1)];
	rep(i,2,ls) lg[i] = lg[i>>1] + 1;
	
	rk[ls+1] = 0x3f3f3f3f;
	rep(i,1,q){	
		scanf("%d%d%d%d%d",&L[i],&R[i],&K[i],&X[i],&Y[i]);
		ans[i] = ls+1;
		if(K[i] <= S) G[K[i]].pb(i);
		else{
			for(int j=0;j*K[i]+X[i]<=ls;j++)
				if(j*K[i]+X[i] <= R[i] && j*K[i]+Y[i] >= L[i]){
					int t = qry(max(j*K[i]+X[i],L[i]),min(j*K[i]+Y[i],R[i]));
					if(cmp2(t,ans[i])) ans[i] = t;
				}
		}
	}
	rep(i,1,S) rep(j,0,i-1){
		st=vc<vi>(lim,vi(ls / i + 5));
		int len;
		for(len=0;i*len+j<=ls;len++) st[0][len] = i*len+j;
		rep(k,1,lim-1) rep(p,0,len-(1<<k)+1) 
			st[k][p] = cmp2(st[k-1][p],st[k-1][p+(1<<k-1)]) ? st[k-1][p] : st[k-1][p+(1<<k-1)];
		for(int v:G[i]) if(X[v] <= j && j <= Y[v]){
			int t = qry((int)ceil((1.0 * L[v]-j) / i) , (int)floor((1.0 * R[v] - j) / i));
			if(cmp2(t , ans[v]))
				ans[v] = t;
		}
	}
	rep(i,1,q) if(ans[i] == ls+1) ans[i] = -1;
	rep(i,1,q)
		printf("%d%c",ans[i]," \n"[i==q]);
}

CF862F Mahmoud and Ehab and the final stage

nn個字符串s[1..n]s[1..n]qq次操作,每次操作是1 l r1\ l\ r表示詢問區間[l,r][l,r]的所有子區間[a,b][a,b]中,lcp(s[a],s[a+1],,s[b])×(ba+1)\operatorname{lcp}(s[a],s[a+1],…,s[b])\times(b-a+1)的最大值。 2 x str2\ x\ str表示把第xx個字符串改成strstrn,q1e5n,q\leq 1e5

容易發現lcp(s[a],s[a+1],,s[b])\operatorname{lcp}(s[a],s[a+1],…,s[b])ba+1b-a+1其中必有一個不會大於n\sqrt n,因爲如果ba+1>nb-a+1 > \sqrt n,則sis_i的長度不可能都>n\gt \sqrt n,所以lcp(s[a],s[a+1],,s[b])n\operatorname{lcp}(s[a],s[a+1],…,s[b]) \leq \sqrt n
所以就維護相鄰兩個字符串的lcplcp數組,每次找出lcpnlcp \geq \sqrt n的位置暴力插入維護答案,同時對於1...n1...\sqrt n每個維護一個線段樹維護區間最長爲11的連續子段即可。
AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 100005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long 
#define pb push_back
#define S 350
#define maxp maxn * 100
using namespace std;

int n,Q,a[maxn];
string s[maxn];

int LCP(const string &a,const string &b){
	int r=0;
	for(;r < a.size() && r < b.size() && a[r] == b[r];r++);
	return r;
}

int lc[maxp],rc[maxp],lx[maxp],rx[maxp],mx[maxp],sz[maxp],bin[maxp],tot,rt[maxn];

int newnode(){
	int r = 0;
	if(bin[0]){
		r = bin[bin[0] --];
		lc[r] = rc[r] = lx[r] = rx[r] = mx[r] = sz[r] = 0;
	}
	else r = ++tot;
	return r;
}

void upd(int u,int l,int m,int r){
	sz[u] = sz[lc[u]] + sz[rc[u]];
	lx[u] = (lx[lc[u]] == m-l+1 ? lx[rc[u]] : 0) + lx[lc[u]];
	rx[u] = (rx[rc[u]] == r-m ? rx[lc[u]] : 0) + rx[rc[u]];
	mx[u] = max(mx[lc[u]] , max(mx[rc[u]] , lx[rc[u]] + rx[lc[u]]));
}

void ins(int &u,int l,int r,int p,int v){
	if(!u) u = newnode();
	sz[u] += v;
	if(l == r){
		lx[u] = rx[u] = mx[u] = sz[u];
		if(!sz[u]) bin[++bin[0]] = u , u = 0;
		return;
	}
	int m = l+r>>1;
	p <= m ? ins(lc[u],l,m,p,v) : ins(rc[u],m+1,r,p,v);
	upd(u,l,m,r);
	if(!sz[u]) bin[++bin[0]] = u , u = 0;
}

void qry(int u,int l,int r,int ql,int qr,int &MX,int &RX){
	if(ql>r||l>qr||!u) return (void)(RX = 0);
	if(ql<=l&&r<=qr) return (void)( MX = max(MX , max(mx[u] , RX + lx[u])) , RX = (rx[u] == r-l+1 ? RX : 0) + rx[u] );
	int m = l+r>>1;
	qry(lc[u],l,m,ql,qr,MX,RX) , qry(rc[u],m+1,r,ql,qr,MX,RX);
}
int c[maxn];
bool cmp(const int &u,const int &v){ return a[u] > a[v]; }
int F[maxn],SZ[maxn];
int Find(int u){ return !F[u] ? u : F[u] = Find(F[u]); }
set<int>mS,mA;

namespace SGT{
	int mx[maxn<<2];
	#define lc u<<1
	#define rc lc|1
	void ins(int u,int l,int r,int p,int v){
		if(l == r) return (void)(mx[u] = v);
		int m = l+r>>1;
		p <= m ? ins(lc,l,m,p,v) : ins(rc,m+1,r,p,v);
		mx[u] = max(mx[lc]  ,mx[rc]);
	}
	int qry(int u,int l,int r,int ql,int qr){
		if(l>qr||ql>r) return 0;
		if(ql<=l&&r<=qr) return mx[u];
		int m = l+r>>1;
		return max(qry(lc,l,m,ql,qr) , qry(rc,m+1,r,ql,qr));
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin >> n >> Q;
	rep(i,1,n){
		cin >> s[i];
		SGT::ins(1,1,n,i,s[i].length());
		if(i > 1){
			a[i-1] = LCP(s[i-1],s[i]);
			if(a[i-1] >= S) mA.insert(i-1);
			rep(j,1, min(a[i-1],S))
				ins(rt[j],1,n-1,i-1,1);
		}
	}
	for(int op,l,r;Q--;){
		cin >> op >> l;
		if(op == 1) {
			cin >> r;
			LL ans = SGT::qry(1,1,n,l,r);
			c[0] = 0;
			for(int v:mA) if(l <= v && v < r) c[++c[0]] = v , F[v] = F[v+1] = 0 , SZ[v] = SZ[v+1] = 1;
			sort(c+1,c+c[0]+1,cmp);
			rep(i,1,c[0]){
				int u = c[i] , v = u + 1;
				F[v] = Find(u);
				SZ[Find(u)] += SZ[v];
				ans = max(ans , 1ll * SZ[Find(u)] * a[u]);
			} 
			rep(i,1,S){
				int MX = 0 , RX = 0;
				qry(rt[i],1,n-1,l,r-1,MX,RX);
				if(MX) ans = max(ans , 1ll * (MX+1) * i);
			}
			printf("%lld\n",ans);
		}
		else{
			if(l > 1){
				if(a[l-1] >= S) mA.erase(l-1);
				rep(j,1,min(a[l-1],S))
					ins(rt[j],1,n-1,l-1,-1);
			}
			if(l < n){
				if(a[l] >= S) mA.erase(l);
				rep(j,1,min(a[l],S))
					ins(rt[j],1,n-1,l,-1);
			}
			cin >> s[l];
			SGT::ins(1,1,n,l,s[l].length());
			if(l > 1){
				a[l-1] = LCP(s[l-1],s[l]);
				if(a[l-1] >= S) mA.insert(l-1);
				rep(j,1, min(a[l-1],S))
					ins(rt[j],1,n-1,l-1,1);
			}
			if(l < n){
				a[l] = LCP(s[l],s[l+1]);
				if(a[l] >= S) mA.insert(l);
				rep(j,1,min(a[l],S))
					ins(rt[j],1,n-1,l,1);
			}
		}
	}
}

CF587F Duff is Mad

在這裏插入圖片描述
還是分塊,我吐了。
對於長度>L> \sqrt L的建出sks_kACAC自動機後暴力查詢sl...srs_l ... s_r的子樹和。
對於長度L\leq \sqrt L的離線在ACAC自動機從s1s_1加到sns_n,然後O(sk)O(|s_k|)ACAC自動機上查詢的父親和,注意修改數是O(n)O(n),查詢數是O(nn)O(n \sqrt n),可以用分塊維護前綴和得到O(nn)O(n \sqrt n)的複雜度。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 100005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define pb push_back
#define LL long long 
#define S 305
using namespace std;

int n,Q;
string s[maxn];
int L[maxn],R[maxn],K[maxn];
LL ans[maxn];
vector<int>in[maxn],ot[maxn],G[maxn<<1];

#define maxc 26
LL sm[maxn];
int last,fa[maxn<<1],tr[maxn<<1][maxc],len[maxn<<1],tot,f[maxn<<1],sa[maxn<<1],c[maxn<<1],pos[maxn];
void ins(int c){
	if(tr[last][c]){
		int p = last , q;
		if(len[q = tr[p][c]] != len[p] + 1){
			int v = ++tot;
			memcpy(tr[v],tr[q],sizeof tr[q]),fa[v] =fa[q] , len[v] = len[p] + 1;
			for(;p != -1 && tr[p][c] == q;p=fa[p]) tr[p][c] = v;
			fa[q] = v;
		}
		last = tr[last][c];
		return;
	}
	int u = ++tot , p = last , q;
	len[last = u] = len[p] + 1;
	for(;p!=-1 && tr[p][c]==0;p=fa[p]) tr[p][c]=u;
	if(p == -1) fa[u] = 0;
	else if(len[q=tr[p][c]] == len[p] + 1) fa[u] = q;
	else{
		int v = ++tot;
		memcpy(tr[v],tr[q],sizeof tr[q]),fa[v] =fa[q] , len[v] = len[p] + 1;
		for(;p != -1 && tr[p][c] == q;p=fa[p]) tr[p][c] = v;
		fa[q] = fa[u] = v;
	}
}

int st[maxn<<1],ed[maxn<<1],tim,ST[maxn<<1],ED[maxn<<1];

void dfs0(int u){
	st[u] = ++tim;
	for(int v:G[u]) 
		dfs0(v);
	ed[u] = tim;
}

int bl[maxn],sb[maxn<<1],id[maxn<<1];
int main(){
	ios::sync_with_stdio(false);
	cin >> n >> Q;
	rep(i,1,n) cin>>s[i];
	rep(i,1,Q){
		cin >> L[i] >> R[i] >> K[i];
		if(s[K[i]].length() <= S) ot[R[i]].pb(i),in[L[i]-1].pb(i);
		else G[K[i]].pb(i);
	}

	rep(i,1,n) if(!G[i].empty()){
		last = 0 , fa[0] = -1;
		rep(j,0,s[i].length()-1) ins(s[i][j]-'a'),f[last]++;
		
		rep(j,0,tot) c[j] = 0;
		rep(j,0,tot) c[len[j]]++;
		rep(j,1,tot) c[j] += c[j-1]; 
		rep(j,0,tot) sa[--c[len[j]]] = j;
		per(j,tot,1){
			int u = sa[j];
			f[fa[u]] += f[u];
		}
		
		rep(j,1,n){
			int u = 0 , L = 0;
			rep(k,0,s[j].length()-1){
				int v = s[j][k] - 'a';
				for(;u != -1 && !tr[u][v];u=fa[u]);
				if(u == -1) u = 0 , L = 0;
				else L = min(L + 1 , len[u] + 1) , u = tr[u][v];
			}
			sm[j] = sm[j-1] + (L == s[j].length()) * (f[u]);
		}
		
		for(int v:G[i])
			ans[v] = sm[R[v]] - sm[L[v]-1];
		G[i].clear();
		
		memset(tr,0,sizeof (tr[0]) * (tot+1));
		rep(j,0,tot) f[j] = 0;
		tot = 0;
	}
	last = 0;fa[0] = -1;
	rep(i,1,n){
		last = 0;
		rep(j,0,s[i].length()-1) ins(s[i][j]-'a');
		pos[i] = last;
	}
	rep(i,1,tot) G[fa[i]].pb(i);
	dfs0(0);
	rep(i,1,tim) id[i] = i / S , ST[id[i]] = ST[id[i]] ? ST[id[i]] : i , ED[id[i]] = i;;
	rep(i,1,n){
		int u = st[pos[i]] , v = ed[pos[i]];
		rep(j,id[u]+1,id[v]-1) bl[j] ++;
		if(id[u] == id[v]){
			rep(j,u,v) sb[j]++;
		}
		else{
			rep(j,u,ED[id[u]]) sb[j]++;
			rep(j,ST[id[v]],v) sb[j]++;
		}
		for(int p:in[i]){
			int u = 0 , t = K[p];
			rep(j,0,s[t].length()-1){
				v = s[t][j] - 'a';
				for(;u != -1 && !tr[u][v];u = fa[u]);
				if(u == -1) u = 0;
				else u = tr[u][v];
				ans[p] -= sb[st[u]] + bl[id[st[u]]]; 
			}
		}
		
		for(int p:ot[i]){
			int u = 0 , t = K[p];
			rep(j,0,s[t].length()-1){
				v = s[t][j] - 'a';
				for(;u != -1 && !tr[u][v];u = fa[u]);
				if(u == -1) u = 0;
				else u = tr[u][v];
				ans[p] += sb[st[u]] + bl[id[st[u]]]; 
			}
		}
	}
	rep(i,1,Q) printf("%lld\n",ans[i]);
}

CF1110H Modest Substrings

LOJ #6681. yww 與樹上的迴文串

給一棵樹,每條邊上有一個字符,求有多少對 (x,y)(x<y)(x,y)(x<y),滿足xxyy路徑上的邊上的字符按順序組成的字符串爲迴文串。

題解:
點分治,然後迴文串分爲兩部分SST+ST+S,其中TTT+ST+S的一個迴文前綴,所以我們建出ACAC自動機,同時用hashhash判斷每個前綴是否是迴文前綴。
算了太毒了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章