zoukankan      html  css  js  c++  java
  • 题解 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;
    }
    
  • 相关阅读:
    消息队列之kafka
    注册中心ZooKeeper
    消息队列之RocketMQ集群部署
    消息队列之RocketMQ简介及单机部署
    消息队列之RabbitMQ
    消息队列简介
    debian10入门(切换root用户,更改网卡配置,及更新apt源配置)
    实体间的关系
    MySQL数据库的基础使用命令大全
    ReletiveLayout布局的一些常用属性
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/12695668.html
Copyright © 2011-2022 走看看