多校 5

D

\(i\)\(j\)均为可行位置,我们需要证明,只有求出\([1,i]\)字典序最小的串有用
这里用\([1,i]\)表示\([1,i]\)的一种方案,\([i,1]\)表示它的翻转
\(4\)\(j\)处的可能情况
\(j\)不翻转
\([1, i]\) + \([i+1,j ]\)
\([i, 1]\) + \([j+1, i]\)
(这种情况可以表示只先进行(或者撤销)\([i, 1]\)翻转
\([j, i +1]\) +\([i, 1]\)只进行\(j\)翻转
\([j, i+1]\) +\([1, i]\)
\([1, i]\)是字典序最小的串,那么几种情况中只有第一种和第四种可能贡献答案,我们将\([1, i]\)的信息维护出来,再判断哪一种字典序更小即可(用hash判断lcp再比较)
具体地,\([1,i]\)的构造过程中有两种字符:在头部插入(对应4)或者在尾部插入(对应1)
我们将其从中间分开,相当于两个队列,插入字符时,我们分别\(O(1)\)维护队列内部的hash,查询前缀hash时候,我们将队列两侧拼起来即可
注意细节:
ull 哈希不能取模,可能在减法时出现负数,爆掉ull
给定一个数字串,你可以翻转前缀,有几个前缀不能翻转,只能从小前缀到大前缀翻转,求最小字典序

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef ll hst;
const int N = 3e5+10;
ll qpow(ll a, ll b, ll MOD){
	ll ret = 1;
	for(;b;b>>=1){
		if(b & 1)  ret = ret * a % MOD;
		a = a * a% MOD;
	}
	return ret;
}
ll inv(ll x, ll MOD){
	return qpow(x, MOD-2, MOD);
}
struct t_ans{
	static const hst base = 37, MOD = 998244353;
	hst pw[N];
	hst operator ()(int ord[], int len){
		hst res = 0;
		pw[0] = 1;
		for(int i = 1; i <= len; ++i) pw[i] = pw[i-1] * base %MOD;
		for(int i = 1; i <= len; ++i){
			res = (res + pw[i-1] * ord[i] % MOD)%MOD;
		}
		return res;
	}
}hscode;
const hst B = 131, MOD = 998244853, iB = inv(B, MOD);
hst base[N], ibase[N];
void init_base(int len){
	ibase[0] = base[0] = 1;
	for(int i = 1; i <= len; ++i) base[i] = (base[i-1] * B)%MOD;
	for(int i = 1; i <= len; ++i) ibase[i] = (ibase[i-1] * iB)%MOD;
}
struct t_seq{
	hst lef[N], rig[N];
	hst strlef[N], strrig[N];
	int cntl, cntr;
	int size(){
		return cntr + cntl;
	}
	void clear(){
		cntl = cntr = 0;
		rig[0] = lef[0] = 0;
	}
	void push_rig(int x){
		++cntr, rig[cntr] = (x + rig[cntr-1] * B)%MOD;
		strrig[cntr] = x;
	}
	void push_lef(int x){
		++cntl, lef[cntl] = (x * base[cntl-1] + lef[cntl-1])%MOD;
		strlef[cntl] = x;
	}
	void pop_rig(){
		--cntr;
	}
	void pop_lef(){
		--cntl;
	}
	hst sub_lef(int l, int r){
		if(l > r) return 0;
		return (lef[r] + MOD- lef[l-1])%MOD * ibase[l-1]%MOD;
	}
	hst sub_rig(int l, int r){
		if(l > r) return 0;
		return (rig[r] - rig[l-1] * base[r-l+1]%MOD)%MOD;
	}
	hst prehash(int r){
		if(r > cntl){
			return (sub_lef(1, cntl) * base[r-cntl]%MOD +  sub_rig(1 ,r-cntl))%MOD;
		}else{
			return sub_lef(cntl-r+1, cntl)%MOD;
		}
	}
	int operator [](int x){
		if(x <= cntl) return strlef[cntl - x + 1];
		return strrig[x - cntl];
	}
	void get_seq(int ord[]){
		for(int i = cntl; i >= 1; --i) ord[++ord[0]] = strlef[i];
		for(int i = 1; i <= cntr; ++i) ord[++ord[0]] = strrig[i];
	}
	void prt(){
		for(int i = 1; i <= size(); ++i){
			cerr<<((*this)[i])<< " ";
		}
		cerr<<endl;
	}
}seq[2];//通常情况下一样
bool check(int mid){
	return seq[0].prehash(mid) == seq[1].prehash(mid);
}
int get_lcp(){
	int res = 0, l = 0, r = seq[0].size();
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid)){
			res = mid;
			l = mid + 1;
		}else{
			r = mid-1;
		}
	}
	return res;
}
int cmp(){
	int res = get_lcp();
	if(res == seq[0].size()) return 0;
	return seq[0][res + 1] < seq[1][res + 1] ? -1 : 1;
}
int n,m;
int a[N];
int res[N];
bool ban[N];
int pre[N];
void solve(){
	seq[0].clear(), seq[1].clear();
	cin >> n >> m;
	init_base(n);
	for(int i = 1; i <= n; ++i) cin >> a[i];
	for(int i = 1; i <= n; ++i) ban[i] = false;
	for(int i = 1; i <= m; ++i){
		int x;cin>>x; ban[x]= true;
	}
	pre[0] = 0;
	for(int i = 1; i <= n; ++i){
		if(ban[i-1]) pre[i] = pre[i - 1];
		else pre[i] = i;
	}
	for(int i = 1; i <= n; ++i){
		if(ban[i]) continue;
		for(int j = pre[i]; j <= i; ++j){
			seq[0].push_rig(a[j]);
		}
		for(int j = pre[i]; j <= i; ++j){
			seq[1].push_lef(a[j]);
		}
		if(cmp() <= 0){//seq[0]更优秀
			for(int j = pre[i]; j <= i; ++j) seq[1].pop_lef();
			for(int j = pre[i]; j <= i; ++j) seq[1].push_rig(a[j]);	
		}else{
			for(int j = pre[i]; j <= i; ++j) seq[0].pop_rig();
			for(int j = pre[i]; j <= i; ++j) seq[0].push_lef(a[j]);
		}
		if(i == 5){
			seq[0].prt();
		}
	}
	if(ban[n]){
		for(int i = pre[n]; i <= n;++i){//插入最后一个非法段
			seq[0].push_rig(a[i]);
		}
	}
	for(int i = 1; i <= n; ++i){
		res[i] = seq[0][i];
	}
	cout << hscode(res, n) << endl;
}
signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--){
		solve();
	}
	return 0;
}
posted @ 2022-07-27 06:59  CDsidi  阅读(23)  评论(0编辑  收藏  举报