1. 程式人生 > >NIKKEI Programming Contest 2019 翻車記

NIKKEI Programming Contest 2019 翻車記

ons ogr 最長 dfs include link font 產生 容易

  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

NIKKEI Programming Contest 2019 翻車記