NIKKEI Programming Contest 2019 翻车记

  A:签到。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a,b;
int main()
{
	/*freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);*/
	n=read(),a=read(),b=read();
	cout<<min(a,b)<<' '<<max(0,a+b-n);
	return 0;
}

  B:签到。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
#define N 110
int n;
char a[N],b[N],c[N];
int main()
{
	/*freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);*/
	n=read();
	scanf("%s",a+1);scanf("%s",b+1);scanf("%s",c+1);
	int ans=0;
	for (int i=1;i<=n;i++)
	{
		if (a[i]==b[i]&&b[i]==c[i]) ;
		else if (a[i]==b[i]||a[i]==c[i]||b[i]==c[i]) ans++;
		else ans+=2;
	}
	cout<<ans;
	return 0;
}

  C:考虑一种菜自己吃和对方吃的收益差,于是显然按ai+bi排序从大到小选即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
#define N 300010
#define ll long long
int n;
struct data
{
	int x,y;
	bool operator <(const data&a) const
	{
		return x+y<a.x+a.y;
	}
}a[N];
ll ans;
int main()
{
	/*freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);*/
	n=read();
	for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
	sort(a+1,a+n+1);reverse(a+1,a+n+1);
	for (int i=1;i<=n;i++)
	if (i&1) ans+=a[i].x;
	else ans-=a[i].y;
	cout<<ans;
	return 0;
}

  D:显然图仍是一个DAG,其中度数为0的点是原树的根。由于图中没有重边,瞎考虑一下容易发现,对于每一个点,由根到它的最长路上该点的前驱即为其在原树中的父亲。拓扑排序一下即可。开始写了个不知道啥玩意于是比E晚了10min。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
#define N 300010
#define ll long long
int n,m,p[N],fa[N],deep[N],degree[N],q[N],t,root;
bool flag[N];
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void topsort()
{
	int head=0,tail=0;
	for (int i=1;i<=n;i++) if (!degree[i]) q[++tail]=i;
	while (tail<n)
	{
		int x=q[++head];
		for (int i=p[x];i;i=edge[i].nxt)
		{
			degree[edge[i].to]--;
			if (deep[x]+1>deep[edge[i].to])
			{
				deep[edge[i].to]=deep[x]+1;
				fa[edge[i].to]=x;
			}
			if (!degree[edge[i].to]) q[++tail]=edge[i].to;
		}
	}
}
int main()
{
	n=read(),m=read();
	for (int i=1;i<n+m;i++)
	{
		int x=read(),y=read();
		addedge(x,y);degree[y]++;
	}
	topsort();
	for (int i=1;i<=n;i++) printf("%d\n",fa[i]);
	return 0;
}
 

  E:显然从大到小考虑每条边是否需要删即可,但删边的过程中难以维护连通块信息。注意到只有MST的边会对最后所得图的连通性产生影响。于是求出MST,然后可以从大到小删边用LCT维护,但这样显然比较毒瘤。事实上还可以建出kruskal重构树,从大到小考虑每条边,如果其在重构树的父亲不需要被删掉,显然其也不需要被删掉;否则此时其所在连通块即为其在重构树上的子树,判断一下是否需要删掉即可。这样就得到了最后的连通信息,最后再考虑每条边是否保留即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
#define N 400010
#define ll long long
int n,m,a[N],fa[N],id[N],cnt,ans;
bool isdel[N],flag[N];
ll value[N<<2];
struct data
{
	int x,y,z;
	bool operator <(const data&a) const
	{
		return z<a.z;
	}
}e[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
namespace kruskal_tree
{
	int p[N<<2],t,degree[N<<2],fa[N<<2];
	ll size[N<<2];
	struct data{int to,nxt;}edge[N<<2];
	void addedge(int x,int y){t++;degree[y]++;fa[y]=x;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
	void link(int x,int y,int i)
	{
		id[i]=++cnt;addedge(cnt,x),addedge(cnt,y);
	}
	void dfs(int k)
	{
		size[k]=a[k];
		for (int i=p[k];i;i=edge[i].nxt)
		{
			dfs(edge[i].to);
			size[k]+=size[edge[i].to];
		}
	}
	void build()
	{
		for (int i=1;i<=cnt;i++)
		if (!degree[i]) dfs(i);
	}
	void del()
	{	
		isdel[0]=1;
		for (int i=m;i>=1;i--)
		if (flag[i]&&isdel[fa[id[i]]]&&e[i].z>size[id[i]]) isdel[id[i]]=1;
	}
}
void dfs(int k)
{
	for (int i=kruskal_tree::p[k];i;i=kruskal_tree::edge[i].nxt)
	{
		dfs(kruskal_tree::edge[i].to);
		if (!isdel[k]) fa[find(kruskal_tree::edge[i].to)]=k;
	}
}
int main()
{
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read();
	sort(e+1,e+m+1);
	for (int i=1;i<=4*n;i++) fa[i]=i;cnt=n;
	for (int i=1;i<=m;i++)
	{
		int p=find(e[i].x),q=find(e[i].y);
		if (p!=q) kruskal_tree::link(p,q,i),fa[p]=fa[q]=id[i],flag[i]=1;
	}
	kruskal_tree::build();
	kruskal_tree::del();
	for (int i=1;i<=cnt;i++) fa[i]=i;
	for (int i=1;i<=cnt;i++)
	if (!kruskal_tree::degree[i]) dfs(i);
	for (int i=1;i<=m;i++)
	if (find(e[i].x)==find(e[i].y)&&kruskal_tree::size[find(e[i].x)]>=e[i].z) ans++;
	cout<<m-ans;
	return 0;
}

  result:rank 132 rating +84

 

posted @ 2019-01-27 22:39  Gloid  阅读(270)  评论(0编辑  收藏  举报