IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> [AGC008F]Black Radius -> 正文阅读

[人工智能][AGC008F]Black Radius

Black Radius

题解

首先考虑以一个点为根向外扩展会得到多少种不同的情形,显然以一个点为根的情况除了全部都染了应该都是不同的,所以情况数有以它为根时最深的点深度 ? 1 -1 ?1种。
但为什么我们不能将1其直接加起来作为总答案呢?当然是因为有几种情况它们得到的结果是一样的。
我们记 f ( i , j ) f(i,j) f(i,j)表示以点 i i i为根,将深度不超过 j j j的点全部染黑得到的树的状况。
可以发现,如果 f ( x , d 1 ) f(x,d_1) f(x,d1?) f ( y , d 2 ) f(y,d_2) f(y,d2?)的树状况一致,那么对于在 x , y x,y x,y的简单路径上的点 z z z,一定存在一个 d d d使得 f ( z , d ) = f ( x , d 1 ) = f ( y , d 2 ) f(z,d)=f(x,d_1)=f(y,d_2) f(z,d)=f(x,d1?)=f(y,d2?)
由于我们的 f ( x , d 1 ) f(x,d_1) f(x,d1?) f ( y , d 2 ) f(y,d_2) f(y,d2?)相同,那么一定有在 x , y x,y x,y的简单路径上,只有一个节点的子树不是全黑的,否则 x , y x,y x,y一定在其中一个子树上染色状况不同。
对于路径上的点 z z z,如果它的子树不是全黑,那么一定满足 d 1 ? d i s ( x , z ) = d 2 ? d i s ( y , z ) d_1-dis(x,z)=d_2-dis(y,z) d1??dis(x,z)=d2??dis(y,z),由于 d i s ( x , z ) + d i s ( y , z ) dis(x,z)+dis(y,z) dis(x,z)+dis(y,z)为定值 d i s ( x , y ) dis(x,y) dis(x,y)所以满足上面条件的 z z z d i s ( x , z ) dis(x,z) dis(x,z) d i s ( y , z ) dis(y,z) dis(y,z)是固定的,所以这样的 z z z是唯一的。
所以必然只有一个点的子树不是全黑的。
那么对于路径上的另一个点 w w w,只要满足 d ? d i s ( w , z ) = d 1 ? d i s ( x , z ) d-dis(w,z)=d_1-dis(x,z) d?dis(w,z)=d1??dis(x,z),于此同时便有 d ? d i s ( x , z ) = d 1 ? d i s ( x , y ) d-dis(x,z)=d_1-dis(x,y) d?dis(x,z)=d1??dis(x,y) d ? d i s ( y , z ) = d 2 ? d i s ( x , y ) d-dis(y,z)=d_2-dis(x,y) d?dis(y,z)=d2??dis(x,y)成立,于是我们一定可以得到相同的染色状况。
同时可以发现,这条路径上的点的 d d d值是呈现一个 V V V形的。
那么我们就可以说明所有可以得到相同树状况的点都是连通的,并且它们中 d d d最小的一定只有一个,同时相邻的点的 d d d值也是连续的。

我们不妨就在这个最小的 d d d上统计答案。
我们考虑一个点满足什么条件时它的 d d d一定是最小的。
我们先不看整棵树都是黑色的情况,那么以该点为根的最高的子树一定不是满的,而且如果我们的根不是唯一解,那么其它子树都应该是全黑的。
由于我们的 d d d值是呈 V V V形,所以除了最小值,其它点必然可以移动到一个 d d d值更小的点去。
显然,我们如果要让这个值更小,那么一定是向着最高的那一棵子树移动,这样我们的 d d d值显然是变小的。
当然,如果这个变小的 d d d值能够到达与原先一样的状态,那么它显然是必须将原来的其它子树都填满的。
于是原先的 d d d一定是得不小于次高子树的高度 + 2 +2 +2的,否则移动后就不满了。
那么如果我们当前值是最小的必要条件就有 d ? h s e c + 1 d\leqslant h_{sec}+1 d?hsec?+1
这样就可以轻松地求出总的不同情况数了。

但我们再看看原题,原题要求不是所有点都可以做根。
如果没有这个条件是很容易用连通块的 ∣ V ∣ ? ∣ E ∣ |V|-|E| V?E容斥解决的,但有了这个就不能这样做了,我们不好求出根只在某个连通块中的情况数。
但实际上我们可以考虑对于原来的 d d d最小的点,找到一个最优秀的替代点,使其作为根时可以得到与原先相同的情况。
显然,这个替代点所在的子树必须是满的,如果在不满的子树的话,我也不可能向其移动,否则一定可以经过一个 d d d更小的点,那样就与我们原先的假设矛盾了。
但移动后我们肯定是有一个下限的,毕竟必须把移动到的那棵子树填满,那我们一定会选择像尽量满的子树移动,这样我们的下限会比较小,也就是涵盖所有合法的情况。

上面的方法很容易就可以用一个换根 d p dp dp实现,显然是线性的。
总时间复杂度 O ( n ) O\left(n\right) O(n)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=924844033;
const int mod=1e5+3;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=2000;
const int lim=1500;
const int M=100000;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-9;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,head[MAXN],tot,mxd[MAXN],cnt[MAXN],num;LL ans;
char str[MAXN];bool key[MAXN];
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void dosaka1(int u,int fa){
	mxd[u]=1;cnt[u]=key[u];
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;if(v==fa)continue;
		dosaka1(v,u);cnt[u]+=cnt[v];
		mxd[u]=max(mxd[v]+1,mxd[u]);
	}
}
void dosaka2(int u,int fa){
	int tmp1=1,tmp2=1,mxm=0,tp=n;if(key[u])tp=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(tmp1<=mxd[v])tmp2=tmp1,tmp1=mxd[v]+1,mxm=cnt[v];
		else if(tmp2<=mxd[v])tmp2=mxd[v]+1;
		if(cnt[v])tp=min(tp,mxd[v]);
	}
	if(mxm<num)ans+=min(tmp1-1,tmp2+1)-tp;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;if(v==fa)continue;
		cnt[u]-=cnt[v];cnt[v]+=cnt[u];
		mxd[u]=(mxd[v]+1==tmp1)?tmp2:tmp1;
		dosaka2(v,u);mxd[u]=tmp1;
		cnt[v]-=cnt[u];cnt[u]+=cnt[v];
	}
}
signed main(){
	read(n);
	for(int i=1;i<n;i++){
		int u,v;read(u);read(v);
		addEdge(u,v);addEdge(v,u);
	}
	scanf("%s",str+1);
	for(int i=1;i<=n;i++)key[i]=str[i]-'0',num+=key[i];
	dosaka1(1,0);dosaka2(1,0);if(num)ans++;
	printf("%lld\n",ans);
	return 0;
}

谢谢!!!

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-02-06 13:50:16  更:2022-02-06 13:51:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 3:30:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码