zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 095

    AtCoder Regular Contest 095


    C - Many Medians

    题意:

    给出n个数,求出去掉第i个数之后所有数的中位数,保证n是偶数。
    (nle 200000)

    分析:

    发现题目范围支持(nlogn)做法。

    我们可以对这些数字建立一棵平衡树,先全加进去,再一边删除一边find一边再加,非常容易想到的解法,但是真要这么写估计排名高不到哪里去。

    考虑删除一个数之后中位数的情况,明显只有两种,一种是你删除的数小于等于中位数,还一种是大于中位数,那么可以先排序找出中位数,然后遍历,判断每个数和中位数的大小关系,可以得出正确结果。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2e5+10;
    int a[MAXN],b[MAXN];
    int main()
    {
    	int n;
    	while(cin>>n){
    		for(int i=1;i<=n;i++){
    			cin>>a[i];
    			b[i]=a[i];
    		}
    		sort(b+1,b+n+1);
    		int mid=n/2;
    		for(int i=1;i<=n;i++){
    			if(a[i]<=b[mid]) cout<<b[mid+1]<<endl;
    			else cout<<b[mid]<<endl;
    		}
    	}
    }
    

    D - Binomial Coefficients

    题意:

    给出n个数,从中选取两个数(a_{i},a_{j}),且(a_ige a_j),使(C_{a_i}^{a_j})最大。
    (nle 100000)

    分析:

    观察题目范围,我们可以用(nlogn)的复杂度解决问题。

    考虑组合数的几个式子:

    1.(C_n^kge C_{n-1}^k)
    2.(C_n^kge C_n^{k-1})

    所以直接找到最大的数(n),然后找到一个最接近于(n/2)的数(k)就一定是最优的。
    发现可以使用平衡树,首先直接全部插入splay中,然后取得最大的,把(n/2)插入,求前驱后继,然后比较一下就行了,但是这么写明显不会有好的排名。

    可以在输入时先找到最大的数,然后再遍历一遍数组,容易找出结果。

    #include <bits/stdc++.h>
    using namespace std;
    int a[1000007],n,id;
    int main()
    {
    	cin>>n;
    	int maxx=-1;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    		if(a[i]>maxx){
    			maxx=a[i];
    			id=i;
    		}
    	}
    	int mid=maxx/2+(maxx%2==1?1:0),ans,cnt=1999999999;
    	for(int i=1;i<=n;i++){
    		if(i==id) continue;
    		if(abs(mid-a[i])<=cnt){
    			cnt=abs(mid-a[i]);
    			ans=a[i];
    		}
    	}
    	cout<<maxx<<" "<<ans;
    }
    

    E - Symmetric Grid

    题意:

    给出一个由字符组成的矩阵,可以任意交换某两行或者某两列,问是否能将这个矩形交换成对称的。

    分析:

    思路非常清晰,代码比较复杂。

    先判断所有行的最终排列,然后在这个基础上check这时的所有列能否满足两两匹配,如果不能匹配的少于两个的话就可能是一个可行解。

    提出另一种解法:可以直接看出每行的各字符数不会发生任何变化,每列的各字符数不会发生任何变化。并且如果找到一组可行解,可以随便配对行列的排列顺序,保证得出的还是一个可行解。

    那么是否可以直接把每行的字符排序之后的字符串扔到一个map里面,然后判断是否能配对,同样我们对列也这么做,貌似可以做到极其优秀的复杂度,不过笔者并没有尝试。

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int MAXN=30;
    char st[MAXN][MAXN];
    int sp[MAXN],ans,used[MAXN];
    int n,m;
    bool check()
    {
    	memset(used,0,sizeof(used));
    	for(int i=0;i<m;i++){
    		if(used[i]) continue;
    		for(int j=0;j<m;j++){
    			bool vis=1;
    			if(i==j||used[j]) continue;
    			for(int k=0;k<n;k++){
    				if(st[k][i]==st[sp[k]][j]) continue;
    				vis=0;
    				break;
    			}
    			if(vis){
    				used[i]=used[j]=1;
    				break;
    			}
    		}
    	}
    	int cnt=0,pos=-1;
    	for(int i=0;i<m;i++)
    		if(!used[i]) cnt++,pos=i;
    	if(cnt>=2||(cnt&&(m%2==0))) return 0;
    	if(cnt==1)
    		for(int i=0;i<n;i++)
    			if(st[i][pos]!=st[sp[i]][pos]) return 0;
    	return 1;
    }
    void dfs(int u,int flag)
    {
    	if(u==(n+1)>>1){
    		if(check()) ans=1;
    		return;
    	}
    	if(ans==1) return;
    	for(int i=u;i<n;i++){
    		if(sp[i]==-1){
    			for(int j=i+1;j<n;j++){
    				if(sp[j]==-1){
    					sp[i]=j;sp[j]=i;
    					dfs(u+1,flag);
    					sp[i]=sp[j]=-1;
    				}
    			}
    			if(flag){
    				sp[i]=i;
    				dfs(u+1,0);
    				sp[i]=-1;
    			}
    		}
    	}
    }
    int main()
    {
    	while(cin>>n>>m){
    		memset(sp,-1,sizeof(sp));
    		ans=0;
    		for(int i=0;i<n;i++) scanf("%s",st[i]);
    		if(n&1) dfs(0,1);
    		else dfs(0,0);
    		if(ans) cout<<"YES"<<endl;
    		else cout<<"NO"<<endl;
    	}
    }
    

    F - Permutation Tree

    题意:

    给你一个序列((p_1,p_2,…,p_n)对于每一个结点)(1,2,…,n)$,两种操作

    1.如果(p_i=1),无需任何操作
    2.如果(p_i≠1),找出最大的j,满足pj<pi,则连接结点i和结点j.

    通过序列((p_1,p_2,…,p_n))可以唯一的构造一棵树。

    题目给你n表示有n个结点,然后n-1条边构造一棵树。问是否可以输出一个((p_1,p_2,…,p_n)) 序列,通过这个序列构造的树和题目给出的树同构,可以的话,输出满足这个条件的最小字典序的序列。无解的话输出-1。

    分析:

    先不分析了。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=4e5+7;
    int head[MAXN],vis[MAXN],size[MAXN],dep[MAXN],nod[MAXN];
    struct po
    {
    	int nxt,to,from;
    }edge[MAXN];
    int n,m,num,cnt,ans=1,s,t,flag=1;
    inline void add_edge(int from,int to)
    {
    	edge[++num].nxt=head[from];
    	edge[num].from=from;
    	edge[num].to=to;
    	head[from]=num;
    }
    inline int bfs(int S)
    {
    	memset(vis,0,sizeof(vis));
    	queue<int> q;
    	q.push(S);
    	vis[S]=1;
    	int u;
    	while(!q.empty()){
    		u=q.front(); q.pop();
    		for(int i=head[u];i;i=edge[i].nxt){
    			int v=edge[i].to;
    			if(!vis[v]){
    				vis[v]=1;
    				q.push(v);
    			}
    		}
    	}
    	return u;
    }
    void dfs(int u)
    {
    	if(!flag) return;
    	int tp=0;
    	vis[u]=1;
    	for(int i=head[u];i;i=edge[i].nxt){
    		int v=edge[i].to;
    		if(!vis[v]){
    			dfs(v);
    			dep[u]=max(dep[u],dep[v]);
    			if(dep[v]>1) tp++;
    			if(v!=t&&dep[v]==1) size[u]++;
    		}
    	}
    	dep[u]++;
    	if(tp>=2){
    		flag=0;
    		return;
    	}
    	if(u!=s&&u!=t&&dep[u]>=2)
    		nod[cnt++]=size[u];
    }
    void out(int u)
    {
    	int tt=ans;
    	vis[u]=1;
    	if(size[u]>0) for(int i=1;i<=size[u];i++) cout<<++ans<<" ";
    	printf("%d%c", tt,u==t?'
    ':' ');
    	ans++;
    	for(int i=head[u];i;i=edge[i].nxt){
    		int v=edge[i].to;
    		if(v==t||v==s||dep[v]>1){
    			if(!vis[v]) out(v);
    		}
    	}
    }
    int main()
    {
    	cin>>n;
    	m=n-1;
    	for(int i=1;i<=m;i++){
    		int u,v;
    		cin>>u>>v;
    		add_edge(u,v);
    		add_edge(v,u);
    	}
    	t=bfs(1);s=bfs(t);
    	memset(vis,0,sizeof(vis));
    	dfs(s);
    	
    	reverse(nod,nod+cnt);
    	for(int i=0;i<cnt;i++){
    		if(nod[i]<nod[cnt-i-1]) break;
    		else if(nod[i]>nod[cnt-i-1]){
    			swap(s,t);
    			break;
    		}
    	}
    	memset(vis,0,sizeof(vis));
    	if(!flag) cout<<"-1";
    	else out(s);
    }
    
  • 相关阅读:
    华为网络层协议介绍
    华为交换机基本原理
    对网络布线与数制转换粗浅认识
    对 计算机网络参考模型新认识
    我对5G的初步认识
    三层交换机单臂路由
    同网段中不同vlan间,客户机从服务器中下载数据
    Telnet远程配置
    华为模拟器里使用RIP协议跨越主类网络边界的实验现象
    7.10 IP地址的格式 以及 网段地址等
  • 原文地址:https://www.cnblogs.com/victorique/p/9582788.html
Copyright © 2011-2022 走看看