题解 CF1335 E,F Three Blocks Palindrome, Robots on a Grid

比赛链接

CF1335E Three Blocks Palindrome

我们直接讲E2(hard version)。

设子序列用到的两个字符分别为(a), (b),它们的出现次数分别为(x), (y)(这和题面中的定义是相同的)。考虑枚举(a),枚举(x),则可以确定左边第(x)(a)的位置,记为(l),右边第(x)(a)的位置,记为(r),我们要做的就是在([l+1,r-1])区间里找出出现次数最多的颜色,作为(b)

如何以优秀的复杂度实现上述思路?

先枚举(a),然后从大到小枚举所有的(x)。在(x)变化时,也就是从(a)的某一个出现位置跳到下一个出现位置时,我们就暴力扫过去。这样的总复杂度是(O(nm))的((mleq 200))。因为是从大到小枚举的(x),发现中间的区间([l+1,r-1])是在不断扩大的,所以可以顺便维护出每个值的出现次数,以及其中的最大值。

时间复杂度(O(nm))

参考代码(片段):

const int MAXN=2e5;
int n,arr[MAXN+5],cnt[205];
int main() {
	int T;cin>>T;while(T--){
		cin>>n;
		for(int i=1;i<=n;++i)cin>>arr[i];
		int ans=0;
		for(int a=1;a<=200;++a){
			vector<pii>vec;
			vec.pb(mk(0,n+1));
			int i=1,j=n;
			while(1){
				while(i<j&&arr[i]!=a)++i;
				while(j>i&&arr[j]!=a)--j;
				if(i>=j)break;
				vec.pb(mk(i,j));++i;--j;
			}
			
			for(int b=1;b<=200;++b)cnt[b]=0;
			int mx=0;
			for(int i=vec.back().fi+1;i<=vec.back().se-1;++i){
				cnt[arr[i]]++;
				mx=max(mx,cnt[arr[i]]);
			}
			i=vec.back().fi;
			j=vec.back().se;
			ans=max(ans,(SZ(vec)-1)*2+mx);
			for(int t=SZ(vec)-2;t>=0;--t){
				while(i>vec[t].fi){
					cnt[arr[i]]++;
					mx=max(mx,cnt[arr[i]]);
					--i;
				}
				while(j<vec[t].se){
					cnt[arr[j]]++;
					mx=max(mx,cnt[arr[j]]);
					++j;
				}
				ans=max(ans,t*2+mx);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

CF1335F Robots on a Grid

每个格子都会唯一对应一个它接下来要走到的格子。我们把所有格子按(1dots nm)编号。将每个格子看做一个节点,从每个节点向它下一步要走到的节点连一条有向边。因为每个点都有且仅有一条出边,我们得到了一个基环内向树森林

问题转化为,让你在一棵基环内向树上,选择若干个点放置robot。进程开始后的每个时刻,每个robot会向前走一条边。要求任意时刻不能有两个robot出现在同一个节点上。在此基础上使得放置的robot数量尽可能多。在满足前面所有条件的基础上使得初始时在黑色节点上的robot尽可能多。

在环上选择一个点(x),断掉(x)(fa[x])之间的边,则基环树变为一棵以(x)为根的树。那么,基环树上,某个节点到(x)的距离,就等于新树上这个节点的深度。我们对新树做一遍dfs求出每个节点的深度。设环长为(len)。则两个节点能同时被放置robot(并且在之后的过程中永远不会撞车),当且仅当它们的深度(mod len)的值不相等。

于是,我们只需要对(0dots len-1)的每个值,求出有没有深度(mod len)等于这个值的节点,有没有黑色节点。

时间复杂度(O(n))

参考代码(片段):

const int MAXN=1e6;
int n,m,c[MAXN+5],fa[MAXN+5],cnt0[MAXN+5],cnt1[MAXN+5],dep[MAXN+5],mxdep,ans1,ans2;
bool vis[MAXN+5],v1[MAXN+5],v2[MAXN+5];
vector<int>G[MAXN+5];
char str[MAXN+5];
inline int id(int i,int j){return (i-1)*m+j;}
void dfs(int u,int frm,const int& root){
	if(!c[u])cnt0[dep[u]]++;else cnt1[dep[u]]++;
	mxdep=max(mxdep,dep[u]);
	vis[u]=1;
	for(int i=0;i<SZ(G[u]);++i){
		int v=G[u][i];
		if(v==frm||v==root)continue;
		dep[v]=dep[u]+1;
		dfs(v,u,root);
	}
}
int main() {
	int T;cin>>T;while(T--){
		cin>>n>>m;
		for(int i=1;i<=n;++i){
			cin>>(str+1);
			for(int j=1;j<=m;++j){
				if(str[j]=='0')c[id(i,j)]=0;
				else c[id(i,j)]=1;
			}
		}
		for(int i=1;i<=n;++i){
			cin>>(str+1);
			for(int j=1;j<=m;++j){
				if(str[j]=='U')fa[id(i,j)]=id(i-1,j);
				if(str[j]=='R')fa[id(i,j)]=id(i,j+1);
				if(str[j]=='D')fa[id(i,j)]=id(i+1,j);
				if(str[j]=='L')fa[id(i,j)]=id(i,j-1);
			}
		}
		n*=m;
		for(int i=1;i<=n;++i)vis[i]=0,vector<int>().swap(G[i]);
		for(int i=1;i<=n;++i){
			G[fa[i]].pb(i);
			//cout<<"edge "<<i<<" "<<fa[i]<<endl;
		}
		ans1=0;ans2=0;
		for(int i=1;i<=n;++i)if(!vis[i]){
			int x=i;
			while(!vis[x]){
				vis[x]=1;
				x=fa[x];
			}
			// take x as root
			//cout<<"root "<<x<<endl;
			dep[x]=0;
			mxdep=0;
			dfs(x,0,x);
			
			int len=dep[fa[x]]+1;
			for(int j=0;j<=mxdep;++j){
				if(cnt0[j]){
					v1[j%len]=1;
					v2[j%len]=1;
				}
				else if(cnt1[j]){
					v1[j%len]=1;
				}
			}
			for(int j=0;j<len;++j){
				ans1+=v1[j];ans2+=v2[j];
			}
			//cout<<"** "<<ans1<<" "<<ans2<<endl;
			for(int j=0;j<=mxdep;++j){
				cnt0[j]=cnt1[j]=0;v1[j]=v2[j]=0;
			}
		}
		cout<<ans1<<" "<<ans2<<endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/dysyn1314/p/12695668.html