首页 > 其他分享 >Atcoder Grand Contest 004(A~F)

Atcoder Grand Contest 004(A~F)

时间:2022-11-09 23:13:27浏览次数:60  
标签:Atcoder 黑色 Contest sum 黑白 节点 终点 004 我们

这场半 VP 做的,就不分赛时赛后写了,直接放每道题的解法。


A - Divide a Cuboid

当某一维的长度为偶数的时候,显然可以在这一维的中间切,两部分方块的最小差为 \(0\)。

当每一维的长度为奇数的时候,设该立方体的大小为 \(n\times m\times f\),则假定我们要切 \(n\) 这一维,我们显然会分给一部分 \(\left\lfloor\frac{n}{2}\right\rfloor\),分给另一部分 \(\left\lceil\frac{n}{2}\right\rceil\)。那么两部分的最小差就是 \(m\times f\)。

于是我们比较 \(n,m,f\) 两两乘积的大小,输出最小的一个乘积即可。


B - Colorful Slimes

当执行操作 \(2\) 的次数为 \(x\) 次时,对于位置 \(i\),贪心地来讲,我们只会 \(a_i\) 及其前面 \(x\) 个 \(a\) 中的最小值作为第 \(i\) 个位置对于答案的贡献。

而有意义的 \(x\) 是满足 \(0\le x<n\) 的,所以我们枚举每一个 \(x\),动态更新每一个 \(a_i\) 当前对于答案的贡献,求和取最小值即可。

时间复杂度 \(O(n^2)\)。


C - AND Grid

观察到一个特殊的条件,边缘的一周是一定不会被涂成紫色的。

所以我们不妨让一种颜色涂满整个边缘,并对于每一个紫色连通块选出一个代表方格 \(a\),并从 \(a\) 开始向上向下拉一条竖线,如果拉的过程中与其它连通块相交就停下,否则直到拉到边缘位置再停下。此时我们就得到了一个颜色的合法涂色。

然后我们将非紫色的连通块 是否涂色 的状态取反,即为另一个颜色的涂色情况。

可以证明这样涂色一定是合法的。时间复杂度 \(O(n^2)\)。


D - Teleporter

首先注意到如果 \(k\) 步之后每一个节点都会积存在根节点,根本原理应该是根节点指向自己,否则深度不同的两个节点最终所在位置一定不同。

那么如果根节点没有指向自己,我们就需要花费一个贡献把它掰回来,然后考虑其它节点。

考虑一种很经典的 trick。我们将所有节点按照深度扔进一个堆中,每次从堆里取出当前深度最大且没有被标记的节点,设根节点深度为 \(0\),如果此时它的深度大于 \(k\),即无法从它出发在 \(k\) 步之内到达根节点,就从它开始向上遍历到它的 \(k-1\) 级祖先,并从每一个祖先出发把儿子中所有未标记的节点进行标记。相当于我们将这棵子树花费一个代价接到根节点上。

一直执行类似操作直到堆空即可。时间复杂度 \(O(n\log n)\).


E - Salvage Robots

从 E 开始难度就上来了,题目也有趣了起来。

首先很容易想到的一点是,机器人太多了,而终点只有一个,所以为了缩减信息,我们不妨将【移动机器人】看作等价的【移动终点及其周围的网格】,再考虑怎么做。

考虑当终点向一个方向移动一步时,另一个方向就会有一列或一行机器人被削掉;当我们确定了向四个方向移动的最远距离的时候,这四个方向最远距离确定的矩形我们显然是都可以再走一遍的,因为全部走一遍不仅不会造成更多的机器人被削掉,还可以获得尽可能更多的贡献,显然不劣。

那么其实我们已经将这道题转化地有了动态规划的雏形。我们只关注当前向四个方向各自走的最远距离,所以不妨设 \(dp_{i,j,p,q}\) 表示从终点向上走 \(i\) 步,从终点向下走 \(j\) 步,从终点向左走 \(p\) 步,从终点向右走 \(q\) 步确定的矩形最多能获得的机器人个数。

转移其实也很清晰了。设终点的坐标为 \(x,y\),不妨考虑向上方多走一步,则此时我们增加的贡献应该是第 \(x-i-1\) 行的一段连续方格的机器人个数,设这个区间为 \([l,r]\),则 \(l\) 应该是我们向左走到的地方,与我们向右走导致左侧削掉的地方的较大值,\(r\) 同理,为我们向右走到的地方,与我们向左走导致右侧削掉的地方的较小值,即 \(l=\max(y-p,q+1),r=\min(y+q,m-p)\)。

其它四个方向的转移同理,转移过程中动态更新答案即可。总时间复杂度 \(O(n^4)\),常数很小。

好像卡空间,只能开 short 储存,求 max min 的时候需要转 int。


F - Namori

顶级思维题。

先从简单的来,考虑树怎么做。首先翻转同色节点显然是不好做的,这会产生很多复杂的情况,并不好处理。

考虑到树是个二分图,所以我们不妨对于树进行一遍黑白染色,将相邻的节点染成不同的颜色,此时我们的问题就变成每次翻转一对相邻的不同颜色节点,需要求出将所有颜色翻转,将黑色节点变成白色,白色节点变成黑色所需要的最少操作次数。那么当黑白节点个数不同的时候,一定无解。

那么每次操作其实就相当于是将一个黑色节点向一个方向挪动一格,我们不妨将这个转化后的问题看作是将黑色节点移动到白色节点上,则这个问题是好做的。

设 \(sum_i\) 为以 \(i\) 为根的子树内黑白节点个数之差,那么节点 \(i\) 对于答案的贡献就是 \(|sum_i|\)。

这意味着对于节点 \(i\),如果黑色节点比白色节点更少,则一定至少会从祖先运来 \(sum_i\) 个黑色节点;反之则一定会至少从这个节点运出 \(sum_i\) 个黑色节点。很容易证明这个【至少】的下界是可以取到的,所以总贡献就是 \(\sum_{i=1}^n sum_i\)。

于是树的问题就解决了。考虑基环树的情况怎么做。

如果这个环的长度是偶数,那么此时这棵基环树也是一个二分图。

依旧是先黑白染色,然后考虑将环上的某一条边作为 dfs 树的一条返祖边,考虑怎么将这条边 \((u,v)\) 拆掉。

设 \(u\) 会向祖先 \(v\) 运送 \(x\) 个黑色节点,则拆掉之后对于原树,从 \(u\) 到 \(v\) 的所有节点的子树中都会少 \(x\) 个黑色节点,则此时该操作会产生影响的贡献为 \(\sum_{p=u}^{p=fa_p}[p\in[v,u]] |sum_p-x|+x\)。

此时我们的目标是想让这个式子取得最小值,易证明当 \(x\) 为所有 \(sum_p\) 的中位数时,该式子的值最小。于是我们得到 \(x\) 的取值后再做一遍加和即可得到答案。

无解的情况依旧是黑白两色节点个数不同。

环长为奇数的情况就麻烦了些,此时染色过后环上会多出一对同色节点。对比在题目要求问题中的翻转条件,我们其实只有在这两个节点同色的时候才能翻转这两个节点的颜色,那么翻转一次就会多出两个黑色节点,或者少两个黑色节点。于是首先易得出当黑白两色节点的个数差为偶数的时候一定有解,否则无解。

不妨设当前整棵树黑白两色节点个数差为 \(s\),则其实这两个节点的唯一作用就是尽量使得 \(|s|\) 变小,因为变大一定是不优的。所以这条边会被使用的次数显然就是 \(\frac{s}{2}\) 次,且会使得这条边两侧的节点子树内黑白两色节点的差都减去 \(\frac{s}{2}\)。于是我们将这条边删去之后,对整棵树再进行一遍树的做法,并在处理到被删除边两侧节点时将差减去 \(\frac{s}{2}\) 即可。

放一下代码吧,感觉结合代码还是会更好理解些。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,m,le,ri,a[N],fa[N],p[N],ptot,g,ans;
bool vis[N],col[N],flag,huan[N];
struct node{
	int head[N],tot,to[N<<1],next[N<<1];
	void adde(int u,int v){
		to[++tot]=v,next[tot]=head[u],head[u]=tot;
	}
}S;
ll read(){
	ll w=0,f=1;
	char c=getchar();
	while (c>'9'||c<'0'){
		if (c=='-') f=-1;
		c=getchar();
	}
	while (c>='0'&&c<='9'){
		w=(w<<3)+(w<<1)+(c^48);
		c=getchar();
	}
	return w*f;
}
void dfs(int u){
	vis[u]=1;
	col[u]=col[fa[u]]^1;
	if (col[u]==1) a[u]=1;
	else a[u]=-1;
	for (int i=S.head[u];i;i=S.next[i]){
		int v=S.to[i];
		if (v!=fa[u]){
			if (vis[v]){
				if (col[v]==col[u]) flag=1;
				le=v,ri=u;
			}else{
				fa[v]=u;
				dfs(v);
				a[u]+=a[v];	
			}
		}
	}
}
int solve(int u){
	int sum=abs(a[u]);
	vis[u]=1;
	for (int i=S.head[u];i;i=S.next[i]){
		int v=S.to[i];
		if (v!=fa[u]&&!vis[v]){
			sum+=solve(v);
		}
	}
	return sum;
}
int dfs2(int u,int x){
	int sum=a[u];
	if (huan[u]) sum-=x;
	sum=abs(sum);
	vis[u]=1;
	for (int i=S.head[u];i;i=S.next[i]){
		int v=S.to[i];
		if (v!=fa[u]&&!vis[v]){
			sum+=dfs2(v,x);
		}
	}
	return sum;
}
void solve2(){
	int now=le;
	while (now!=ri){
		huan[now]=1;
		p[++ptot]=a[now];
		now=fa[now];
	}
	sort(p+1,p+1+ptot);
	cout<<dfs2(1,p[ptot/2+1])+abs(p[ptot/2+1])<<'\n';
}
int solve3(int u,int x){
	int now=0;
	if (col[u]==1) now++;
	else now--;
	if (u==le||u==ri) now-=x;
	vis[u]=1;
	for (int i=S.head[u];i;i=S.next[i]){
		int v=S.to[i];
		if (v!=fa[u]&&!vis[v]){
			now+=solve3(v,x);
		}
	}
	ans+=abs(now);
	return now;
}
void solve3(){
	int x=g/2;solve3(1,x);
	cout<<ans+abs(x)<<'\n';
}
signed main(){
	n=read(),m=read();
	for (int i=1;i<=m;i++){
		int u=read(),v=read();
		S.adde(u,v),S.adde(v,u);
	}
	dfs(1);
	for (int i=1;i<=n;i++){
		if (col[i]) ++g;
		else --g;
	}
	if (g!=0&&!flag||abs(g)%2!=0&&flag){
		puts("-1");
		return 0;
	}
	memset(vis,0,sizeof(vis));
	if (m==n-1) cout<<solve(1)<<'\n';
	else if (!flag) solve2();
	else solve3();
	return 0;
}

标签:Atcoder,黑色,Contest,sum,黑白,节点,终点,004,我们
From: https://www.cnblogs.com/ydtz/p/16875536.html

相关文章

  • The 2022 ICPC Asia Regionals Online Contest (II)
    一直没补,把之前的粘贴过来EAnInterestingSequence 为使数组和小,并且gcd=1,我们添加2,3,,找到第一个不整除k的质数,然后后面放2,3,判断先放2还是3JAGameaboutIncrea......
  • 关于异常DBG_TERMINATE_PROCESS(0x40010004)
    简介DBG_TERMINATE_PROCESS表示进程被调试器终止。值为0x40010004。其定义如下:////MessageId:DBG_TERMINATE_PROCESS////MessageText:////Debuggerterminatedproce......
  • 700004 TXT 建筑的分类
    “建筑”指人工建筑而成的资产,属于固定资产范畴,是建筑物和构筑物的总称。为人们提供生活、学习、工作、居住以及从事生产和文化活动的房屋或场所称为建筑物。其他如水池、......
  • 611004 CAD 直线构造线多段线
    本节课讲解4CAD直线构造线多段线。1.左侧工具栏第一个为直线命令,快捷键【L】,根据命令栏提示进行绘图。2.绘制直线,输入长度,要转换为毫米,点击【空格】。3.【DI】可以......
  • The 2020 ICPC Asia Shenyang Regional Programming Contest
    VP题目列表D.JourneytoUn'GoroF.KoboldsandCatacombsG.TheWitchwoodH.TheBoomsdayProjectI.RiseofShadowsJ.DescentofDragonsK.S......
  • AtCoder Beginner Contest 275
    A-FindTakahashi找到序列中最高的数存在的位置#include<bits/stdc++.h>usingnamespacestd;intread(){intx=0,f=1,ch=getchar();while((c......
  • Atcoder Beginner Contest 276(A~G)
    赛时A简单字符串处理;B简单vector处理;C找上一个排列。D找到每一个数因子\(2\)的个数和\(3\)的个数,并判断除去这些因子之后剩下的值是否相同,若不同则不能满足条......
  • AtCoder Beginner Contest 276
    A-Rightmost#include<bits/stdc++.h>usingnamespacestd;int32_tmain(){strings;cin>>s;for(inti=s.size();i>=1;i--)i......
  • [Leetcode Weekly Contest]318
    链接:LeetCode[Leetcode]2460.对数组执行操作给你一个下标从0开始的数组nums,数组大小为n,且由非负整数组成。你需要对数组执行n-1步操作,其中第i步操作(从0......
  • 004 Web Assembly康威游戏之优化
    0介绍视频地址:https://www.bilibili.com/video/BV1eg411g7c8相关源码:https://github.com/anonymousGiga/Rust-and-Web-Assembly1说明在上一节的实现中,我们是在Rust中实现......