CF1877 E. Autosynthesis 基环树dp

传送门:CF

[前题提要]:一道基环树dp,但是题目有点绕,当时卡了我整整半天,到了第二天换了和清醒的脑子然后和别人讨论才整明白,故记录一下

题目很绕,故不再介绍.

首先对于这种下标和值有关系的题目.其实不难想到建图(CF上有大量这种 t r i c k trick trick),随便举个类似的题目:CF1768D.所以我们考虑每一个位置下标连向值建图.(注意我们建出来的图中的所有点都是点下标之前的关系)

首先,按照套路,每一个点都有且只有一条出边,也就是每一个点的出度都为1,那么这张图其实是一棵内向基环树.

然后想一下这样建图有什么意义.我们发现我们圈出一个点,其实多出来的是这个点的下标的贡献,那么我们想要选出这个点,按照题意,我们得需要一个值为我们选出来的点的下标的点留下来.那么这个点在哪里呢.就是我们选出来的这个点的入点.(请仔细理解这一部分).

所以我们想要选出一个点,必须得存在一个入点留下来.

然后我们考虑一个点想要留下来.要满足什么条件.我们一个点留下来了,多出来的是这个点的值的贡献,所以我们得需要一个下标为这个值的点被选出来.这个点在哪里呢,这个点显然就是我们当前点的出点.(因为我们每一个点都指向下标为该点值的点).


总结一下就是:
一个点想要留下来,它的父亲必须删除.一个点想要删除,必须存在一个儿子留下来

然后根据上述结论,其实我们不难发现,叶子节点都是得保留下来的,因为没有一个点指向叶子节点,也就是,没有一个点的值等于我们的叶子结点的下标

所以我们考虑对这棵基环树进行拓扑(其实这也是基环树dp的经典套路,拓扑排序).从叶子节点开始倒推,一步一步的确定每一个点的状态(此时我们会发现一个点的状态其实是一定的,因为有一个点只要有儿子留下来,该点就必须删除,没有儿子留下来的时候,该点又只能留下来).所以我们可以使用树形 d p dp dp来推出每一个根节点的状态(保留或者删除).

这里补一下上述做法:因为该图是一个基环树,按照经典做法,我们考虑求出环上的每一个点,那么对于每一个点来说,他都是一棵树的根节点(基环树的性质).所以我们可以对每一个根节点形成的树进行树形 d p dp dp.然后求出每一个根节点的状态最后进行环形 d p dp dp.

所以我们现在是求出了环上每一个点的状态.所以我们考虑环上该怎么办.
详细讨论一下就会发现存在以下几种情况:

  1. 环上的每一个点独立状态都是保留.此时需要注意的是,我们环上的点其实相互都是有入点和出点的.所以此时的保留状态其实是可以变为删除状态的.此时我们只要随便选一个点保留,然后对应的出点需要删除.显然的,我们会发现只要是奇数点必然会出现矛盾,是偶数环则不会.
  2. 环上存在一个点是删除状态的.我们考虑从这个删除状态出发.因为环上一个点如果删除了.它的出点就不会有这个点的贡献.所以出点如果是删除状态,那么还是删除状态;如果是保留状态,那么需要变为删除状态,然后使用之前的性质递推下去.这里需要注意的是,我们需要从删除状态出发.

举个栗子:

在这里插入图片描述

0代表独立状态为删除,1代表保留.如果我们从下面那个3出发,我们会发现4变为0,3也变为0.但是当3变为0的时候,4不能变为0.所以此时出现了问题.
但是为什么从0出发就没有问题呢.因为从0出发,我们最后循环到自己这个位置的时候因为他是0,所以无论后面是1还是0,他都可以是0(不会对初始状态产生影响).所以我们会发现这样构造一定是成立的.

还有一点需要注意的是,本题可能是一个基环树森林


下面是具体的代码部分:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
inline void print(__int128 x){
	if(x<0) {putchar('-');x=-x;}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
#define maxn 1000000
#define int long long
const int mod=998244353;
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];vector<int>edge[maxn];
int in[maxn];int n;int vis[maxn],mp[maxn];int cnt=0;
void dfs(int u,int per_u) {//找环
	for(auto v:edge[u]) {
		if(v==per_u) continue;
		if(in[v]==1||vis[v]==1) continue;
		mp[++cnt]=v;vis[v]=1;
		dfs(v,u);
	}
}
int state[maxn];//1保留,0删除
void solve(int u,int per_u) {//树形dp
	if(edge[u].size()==1) {
		state[u]=1;return ;
	}
	int this_cnt=0;
	for(auto v:edge[u]) {
		if(v==per_u) continue;
		if(in[v]==2) continue;
		solve(v,u);
		this_cnt+=state[v];
	}
	if(this_cnt!=0) state[u]=0;
	else state[u]=1;
}
void init() {
	for(int i=1;i<=cnt;i++) {
		mp[i]=0;
	}
}
int flag=0;
void topo() {
	queue<int>q;
	for(int i=1;i<=n;i++) {
		if(in[i]==1) {
			q.push(i);
		}
	}
	while(!q.empty()) {
		int u=q.front();q.pop();
		for(auto v:edge[u]) {
			in[v]--;
			if(in[v]==1) {
				q.push(v);
			}
		}
	}
	for(int i=1;i<=n;i++) {
		if(in[i]==2&&vis[i]==0) {
			cnt=0;
			mp[++cnt]=i;vis[i]=1;
			dfs(i,0);
			for(int j=1;j<=cnt;j++) {
				solve(mp[j],0);
			}
			int pos=0;int this_cnt=0;
			for(int j=1;j<=cnt;j++) {
				this_cnt+=state[mp[j]];
				if(state[mp[j]]==0) {
					pos=j;
				}
			}
			if(this_cnt==cnt) {//全是1,说明可以乱填,但如果是奇数,不行
				if(cnt&1) {
					flag=1;break;
				}
				else {
					int num=1;
					for(int j=1;j<=cnt;j++) {
						state[mp[j]]=num;num^=1;
					}
				}
			}
			else {//如果不是,那么如果一个点没有儿子,那这个1不能变成0
				//反之可以变为0(因为环中也可以保留点),所以应该从0出发
				for(int j=pos;j<=pos+cnt-1;j++) {
					if(state[mp[(j-1+cnt)%cnt+1]]==1) {
						if(state[mp[(j+cnt)%cnt+1]]) {
							state[mp[(j+cnt)%cnt+1]]=0;
						}
					}
				}
			}
			if(flag) break;
			init();
		}
	}
	if(flag) {
		cout<<-1<<endl;
	}
	else {
		int this_cnt=0;
		for(int i=1;i<=n;i++) {
			if(state[i]==1) {
				this_cnt++;
			}
		}
		cout<<this_cnt<<endl;
		for(int i=1;i<=n;i++) {
			if(state[i]==1) {
				cout<<a[i]<<" ";
			}
		}
		cout<<endl;
	}
}
signed main() {
//	freopen("input.in","r",stdin);
//	freopen("output.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++) {
		a[i]=read();
		edge[i].push_back(a[i]);
		edge[a[i]].push_back(i);
		in[i]++;in[a[i]]++;
	}
	topo();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/208977.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOs 4 (一) 认识HarmonyOs

目录 一 HarmonyOs 背景1.1 发展时间线1.2 背景分析1.2.1 新场景1.2.2 新挑战1.2.3 鸿蒙生态迎接挑战 二 HarmonyOS简介2.1 OpenHarmony2.2 HarmonyOS Connect2.3 HarmonyOS Next**2.4 ArkTS &#xff08;重点掌握&#xff09;****2.5 ArkUI** 三 鸿蒙生态应用核心技术理念**3.…

Gavin Wood:财库保守主义偏离了初心,应探索 Fellowship 等更有效的资金部署机制

波卡创始人 Gavin Wood 博士最近接受了 The Kusamarian 的采访&#xff0c;分享了他的过往经历、对治理的看法&#xff0c;还聊到了 AI、以太坊、女巫攻击、财库等话题。本文整理自 PolkaWorld 对专访编译的部分内容&#xff0c;主要包含了 Gavin 对治理、财库提案、生态资金分…

re:Invent大会,亚马逊云科技为用户提供端到端的AI服务

11月末&#xff0c;若是你降落在拉斯维加斯麦卡伦国际机场&#xff0c;或许会在大厅里看到一排排AI企业和云厂商相关的夸张标语。走向出口的路上&#xff0c;你的身边会不断穿梭过穿着印有“AI21Lab”“Anthropic”等字样的AI企业员工。或许&#xff0c;你还会被机场工作人员主…

PyQt基础_014_对话框类控件QFileDialog

基本操作 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class filedialogdemo(QWidget):def __init__(self, parentNone):super(filedialogdemo, self).__init__(parent)layout QVBoxLayout()self.btn QPushButton("…

【Linux】cp 命令使用

cp 命令 cp&#xff08;英文全拼&#xff1a;copy file&#xff09;命令主要用于复制文件或目录。 著者 由Torbjorn Granlund、David MacKenzie和Jim Meyering撰写。 语法 cp [选项]... [-T] 源文件 目标文件或&#xff1a;cp [选项]... 源文件... 目录或&#xff1a;cp [选…

SpringBoot 集成 ChatGPT,实战附源码

1 前言 在本文中&#xff0c;我们将探索在 Spring Boot 应用程序中调用 OpenAI ChatGPT API 的过程。我们的目标是开发一个 Spring Boot 应用程序&#xff0c;能够利用 OpenAI ChatGPT API 生成对给定提示的响应。 您可能熟悉 ChatGPT 中的术语“提示”。在 ChatGPT 或类似语…

UDS诊断服务

UDS诊断服务 什么是UDS&#xff1f; UDS – Unified diagnostic services (统一诊断服务) 俗称14229. 形象的说&#xff1a;就是使用一套仪器&#xff0c;对当前汽车出现的问题进行分析。而这套仪器与汽车交谈所使用的语言就是UDS&#xff08;不是唯一的方法&#xff09;。 …

【Linux系统化学习】揭秘 命令行参数 | 环境变量

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 代码仓库&#xff1a;Gitee 目录 命令行参数 环境变量 PATH 查看PATH $PWD 查看环境变量PWD $HOME 查看系统支持的环境变量 获取环境变量 命令行参数 在C/C编程语言中我们有一个…

domjudge题目配置和开比赛

系统使用的是7.3.3&#xff0c;domjudge配置的方法请参考前文 domjudge配置-CSDN博客 题目导入 传统比较 首先可以去domjudge中随便下载一个题目&#xff0c;下载下来的压缩包应该是这样的 │ domjudge-problem.ini │ problem.pdf │ problem.yaml │ └─data└─sec…

西南科技大学(数据结构A)期末自测练习五

一、选择题&#xff08;每空 1 分&#xff0c;共 5 分&#xff09; 1、下面关于图的叙述中&#xff0c;正确的是&#xff08; &#xff09;。 (1)&#xff0e;回路是简单路径 (2)&#xff0e;存稀疏矩阵&#xff0c;用邻接矩阵比邻接表更省空间 (3)&#xff0e;若有像图中存在…

网页开发 JS基础

目录 JS概述 基本语法 数据类型内置方法 DOM对象 查找标签 绑定事件 操作标签 jQuery 查找标签 绑定事件 操作标签 Ajax请求 数据接口 前后端分离 ajax的使用 JS概述 一门弱类型的编程语言,属于基于对象和基于原型的脚本语言. 1 直接编写<script>console…

numpy知识库:深入理解numpy的repeat函数和numpy数组的repeat方法

前言 numpy中的repeat函数顾名思义&#xff0c;可以将给定的数组沿着指定的轴重复多次&#xff0c;生成一个新的数组。但具体如何重复呢&#xff1f;本次博文就来探讨并试图回答这个问题&#xff0c;感兴趣的小伙伴可以继续阅读下去&#xff0c;希望对你有所启示~ numpy中的r…

Linux基本指令(后篇)

目录 14.时间指令date 15.Cal指令 16.find指令(非常重要) 17.grep指令 18.打包压缩指令zip和tar以及解压指令unzip和tar 14.时间指令date date(显示当前时间) 1.在显示方面&#xff0c;使用者可以设定欲显示的格式&#xff0c;格式设定为一个加号后接数个标记&#xff0c;其中…

企业存货库存综合分析全流程图

上期我们谈到了 诊断存货管理的4大维度&#xff0c;今天我们进一步全方位、全周期的分析企业内存货的问题。 企业存货是企业用于生产或销售的货品&#xff0c;是企业价值增值变现的载体&#xff0c;但是如果一旦没有产生交易&#xff0c;存货就很有可能带来损失。存货伴随着企业…

C#基础与进阶扩展合集-进阶篇(持续更新)

目录 本文分两篇&#xff0c;基础篇点击&#xff1a;C#基础与进阶扩展合集-基础篇 二、进阶扩展 1、Predicate 2、设置C#语言版本 3、ListCollectionView过滤集合 4、Adapt适配器 5、值类型与引用类型 6、程序设置当前项目工作目录 7、获取App.config配置文件中的值 …

Mysql多表查询 子查询

目录 关联查询——cross join 概述&#xff1a; 关联查询 inner join 概述&#xff1a; 关联查询 outher join 概述&#xff1a; inner join 和outher join 的区别 子查询 IN 概述 IN 分析 子查询 exists exists 分析 SQL之母 - SQL自学网站SQL自学网站http://sqlmo…

冒个泡!OceanBase亮相 2023 新加坡金融科技节

近日&#xff0c;OceanBase 亮相 Singapore Fintech Festival 2023&#xff08;2023 新加坡金融科技节&#xff09;&#xff01;本届新加坡金融科技节于 2023 年 11 月 15 日至 17 日在新加坡博览展览中心举行&#xff0c;展会期间&#xff0c;OceanBase 得到了众多金融科技机构…

2023-12-01 AIGC-自动生成ppt的AI工具

摘要: 2023-12-01 AIGC-自动生成ppt-记录 自动生成ppt: BoardMix boardmix 一键生成ppt boardmix是一款基于云的ai设计软件&#xff0c;允许创建用于各种目的的自定义演示文稿、ai绘画&#xff0c;ai生成思维导图等。以下是它的一些功能&#xff1a; 可定制的模板 - 它有一个…

无人机助力电力设备螺母缺销智能检测识别,python基于YOLOv5开发构建电力设备螺母缺销小目标检测识别系统

传统作业场景下电力设备的运维和维护都是人工来完成的&#xff0c;随着现代技术科技手段的不断发展&#xff0c;基于无人机航拍飞行的自动智能化电力设备问题检测成为了一种可行的手段&#xff0c;本文的核心内容就是基于YOLOv7来开发构建电力设备螺母缺销检测识别系统&#xf…

从0开始学习JavaScript--JavaScript ES6 模块系统

JavaScript ES6&#xff08;ECMAScript 2015&#xff09;引入了官方支持的模块系统&#xff0c;使得前端开发更加现代化和模块化。本文将深入探讨 ES6 模块系统的各个方面&#xff0c;通过丰富的示例代码详细展示其核心概念和实际应用。 ES6 模块的基本概念 1 模块的导出 ES…