Luogu P6185 【[NOI Online 提升组]序列】

原本考场切了的,结果代码没保存,爆炸成80,自闭了。
考场上我是一个一个部分分作的,因此这里我也一个一个部分分写。数组

0pts \(n=1\)

这个档位是针对样例写的。。。由于不写我就过不了样例。。。
显然若是有一个1操做就输出YES,没有就看相不相等完事。。。
贴一个没有什么用的代码。spa

inline void Solve_0pts()
{
	if(flg1==1) 
	{
		printf("YES\n");
	}
	else 
		if(a[1]==b[1])
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
		return ;
}

60pts \(n=2\)

分类讨论:

1.若是只有1操做,那很显然,只要\(a1-b1=a2-b2\)就完事了。
2.若是只有2操做,那也很显然,只要\(a1-b1==b2-a2\)就完事了。
3.若是1,2操做都有,那么假设\(a1+k1+k2=b1\),\(a2+k1-k2=b2\),合并一下就能够获得\(a1+a2-b1-b2=-2*k2\),因此只要做差而后断定一下是否是偶数就能够了。
贴一个有点用的代码。code

inline void Solve_60pts()
{
	if(flg1)
	{
		if(a[1]-b[1]==a[2]-b[2])
		{
			printf("YES\n");
			return;
		}
	}
	if(flg2)
	{
		if(a[1]-b[1]==b[2]-a[2])
		{
			printf("YES\n");
			return;
		}
	}
	if(flg1&&flg2)
	{
		if((a[1]+a[2]-b[1]-b[2])%2==0)
		{
			printf("YES\n");
			return;
		}
	}
	printf("NO\n");
}

80pts \(ti=2\)

发现被连接的两个点的值能够互相流动,因而把连接的点在a和b数列里分别缩点,这里用并查集实现。因为同一个集合里的点的值能够互相流动,因此这里只要a数列和b数列每一个对应集合里的点权和相同,那么就必定是合法的,不然不合法,代码也比较好写。string

inline int find(int x) 
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}

inline void merge(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	va[fy]+=va[fx];
	va[fx]=0;fa[fx]=fy;
}

inline void Solve_80pts()
{
	for(R int i=1;i<=n*2;i++) fa[i]=i;
	for(R int i=1;i<=n;i++) va[i]=a[i];
	for(R int i=1;i<=n;i++) va[n+i]=b[i];
	for(R int i=1;i<=m;i++)
	{
		int x=u[i],y=v[i];
		if(find(x)==find(y)) continue;
		merge(x,y);
		merge(x+n,y+n);
	}
	for(R int i=1;i<=n;i++)
		if(find(i)==i)
		{
			if(va[i]!=va[i+n])
			{
				printf("NO\n");
				return;
			}
		}
	printf("YES\n");
}

100pts

为了方便,先用一个sm数组存下a与b对应位置的差值。
发现80分缩点的作法十分温馨,因此先把操做2缩点,而后就只剩下操做1了。因为操做2已经缩点,操做1再缩点感受不太现实,因而考虑连边(好玄学)。 把1操做的两个点连边以后(注意是连缩点以后的)。而后继续开始手玩样例,发现假若有两个点\((x,y)\),使得这两个点之间有一条长度为偶数的路径,那这两个点之间也是能够相互交流权值的。更特别一点的是,若是一个联通块里面有一个长度为奇数的环,那任意两个点之间都会有一条长度为偶数的路径。为何呢,由于环上的点显然是有的,环外的点若是到一个点不通过环长度为奇数,那就去跑一边环就变成偶数了,因此这个命题成立。而后就能够把有奇环的联通块当作一个点了。那么这样的一个块,
若是差值的和或者差是偶数,就是能够的,不然就不行。注意若是一个点连成了自环,那么也是能够的算成这一种块。若是这个块刚好是一个二分图,那么黑白染色以后,权值就只能够在黑点集合中的点之间和白点集合中的点之间各自流动,由于同一个集合中的任意两个点的距离一定是偶数。因此就计算黑点差值之和与白点的差值之和是否相同就能够了。个人代码中没有统计和,是直接一边染色一边相减的。对于单独的点,咱们也把它当作一个二分图来处理便可。部分代码就懒得丢了,就是完整代码里100pts的部分(忽然反应过来,那我上面丢代码干啥???)it

完整代码

#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

#define R register
#define ll long long
const int MAXN=2e5+10;

int n,m;
int a[MAXN],b[MAXN];
int opt[MAXN],u[MAXN],v[MAXN];

int flg1=0,flg2=0;

inline void Init()
{
	scanf("%d%d",&n,&m);
	for(R int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(R int i=1;i<=n;i++)	scanf("%d",&b[i]);
	flg1=flg2=0;
	for(R int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&opt[i],&u[i],&v[i]);
		if(opt[i]==1) flg1=1;
		if(opt[i]==2) flg2=1;
	}

}

inline void Solve_0pts()
{
	if(flg1==1) 
	{
		printf("YES\n");
	}
	else 
		if(a[1]==b[1])
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
		return ;
}

inline void Solve_60pts()
{
	if(flg1)
	{
		if(a[1]-b[1]==a[2]-b[2])
		{
			printf("YES\n");
			return;
		}
	}
	if(flg2)
	{
		if(a[1]-b[1]==b[2]-a[2])
		{
			printf("YES\n");
			return;
		}
	}
	if(flg1&&flg2)
	{
		if((a[1]+a[2]-b[1]-b[2])%2==0)
		{
			printf("YES\n");
			return;
		}
	}
	printf("NO\n");
}

int fa[MAXN];
ll va[MAXN];

inline int find(int x) 
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}

inline void merge(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	va[fy]+=va[fx];
	va[fx]=0;fa[fx]=fy;
}

inline void Solve_80pts()
{
	for(R int i=1;i<=n*2;i++) fa[i]=i;
	for(R int i=1;i<=n;i++) va[i]=a[i];
	for(R int i=1;i<=n;i++) va[n+i]=b[i];
	for(R int i=1;i<=m;i++)
	{
		int x=u[i],y=v[i];
		if(find(x)==find(y)) continue;
		merge(x,y);
		merge(x+n,y+n);
	}
	for(R int i=1;i<=n;i++)
		if(find(i)==i)
		{
			if(va[i]!=va[i+n])
			{
				printf("NO\n");
				return;
			}
		}
	printf("YES\n");
}

int To[MAXN+MAXN],Next[MAXN+MAXN],Head[MAXN],cnt;

inline void add(int x,int y)
{
	cnt++;
	To[cnt]=y;
	Next[cnt]=Head[x];
	Head[x]=cnt;
}

int sm[MAXN];
int co[MAXN];

int sum,tag;

inline void dfs(int x,int col)
{
	co[x]=col;
	if(col) sum+=sm[x];
	else sum-=sm[x];
	for(R int i=Head[x];i;i=Next[i])
	{
		int y=To[i];
		if(co[y]==-1)
			dfs(y,col^1);
		else
			if(co[x]==co[y]) tag=1;
	}
}

inline void Solve_100pts()
{
	memset(Head,0,sizeof(Head));
	memset(co,-1,sizeof(co));
	cnt=0;
	for(R int i=1;i<=n;i++)
		sm[i]=a[i]-b[i];
	for(R int i=1;i<=n;i++)
		fa[i]=i;
	for(R int i=1;i<=m;i++)
	{
		if(opt[i]==1) continue;
		int x=u[i],y=v[i];
		if(find(x)==find(y)) continue;
		int fx=find(x),fy=find(y);
		fa[fx]=fy;sm[fy]+=sm[fx];sm[fx]=0;
	}
	for(R int i=1;i<=m;i++)
	{
		if(opt[i]==2) continue;
		int x=u[i],y=v[i];
		x=find(x);y=find(y);
		add(x,y);add(y,x);
	}
	bool flg=1;
	for(R int i=1;i<=n;i++)
		if(find(i)==i&&co[i]==-1)
		{
			sum=tag=0;
			dfs(i,0);
			for(R int j=Head[i];j;j=Next[j])
				if(To[j]==i) tag=1;
			if(tag==1)
			{
				if(sum%2!=0) flg=0;
			}
			else
			{
				if(sum!=0) flg=0;
			}

		}
	if(flg) printf("YES\n");
	else printf("NO\n");
}

int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	int test;scanf("%d",&test);
	while(test--)
	{
		Init();
		if(n==1) {Solve_0pts(); continue;}
		if(n<=2) {Solve_60pts();continue;}
		if(flg1==0&&flg2==1) {Solve_80pts();continue;}
		Solve_100pts();
	}
	return 0;
}

然而这并不能改变我总分100的事实,自闭了。。。io

相关文章
相关标签/搜索