专栏文章

题解:P13956 [ICPC 2023 Nanjing R] 等价重写

P13956题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mio0n33m
此快照首次捕获于
2025/12/02 11:25
3 个月前
此快照最后确认于
2025/12/02 11:25
3 个月前
查看原文
[Analysis]\color{blue}{\texttt{[Analysis]}}
思路参考了官方题解。
赋值操作的特点是最终的结果只和最后一次赋值操作有关。
构造这么一张有向图 GG:边 iji \to j 存在当且仅当 i<ji<j,且操作 pip_{i}pjp_{j} 同时对某个位置 tt 进行了重赋值,jj 是最后一次对 tt 进行了赋值的操作
满足了这三个条件,则在原来的操作顺序下,tt 位置最终一定是 jj 而不是 ii。因此在合法的答案中,jj 也必须在 ii 的后面,不然 tt 位置的值就改变了。
GG任意一个拓扑序均是合法的答案(除 1,2,,n1,2,\dots,n 外)。
当然我们不能显式的把图 GG 建立,因为那样图可能很大,且不方便寻找满足条件的拓扑序。
因为只要输出一个合法方案就行,我们考虑限制一下我们的操作。不妨考虑只能交换相邻的两个操作。
定理:如果存在合法的方案,则一定存在一种方案,它只交换了相邻的两个操作。
  • 证明:
    • 如果不存在这样的方案,则代表原图存在所有的 (i1)i(i-1) \to i 的边(2in,iN2 \leq i \leq n,i \in \mathbb{N})。
    • 那么原图的拓扑序就只有 1234n1 \to 2\to 3 \to 4 \to \dots \to n 这一种,不存在其它的合法方案。
    • 因此,如果存在合法方案,一定存在一种方案,只交换了相邻的两个操作。
因此只需要对相邻的两个操作进行判断即可。
Code\color{blue}{\text{Code}}
CPP
const int N=1e5+100;

int p[N],n,m,ans[N],lst[N];
vector<int> pos[N];

void init(int n,int m){
	for(int i=1;i<=n;i++) ans[i]=i;
	for(int i=1;i<=n;i++) pos[i].clear();
	for(int i=1;i<=m;i++) lst[i]=0;
}

int OZDY(){
	n=read();m=read();
	
	init(n,m);
	
	for(int i=1;i<=n;i++){
		p[i]=read();
		for(int j=1;j<=p[i];j++){
			int u=read();
			pos[i].push_back(u);
			lst[u]=i;
		}
		
		sort(pos[i].begin(),pos[i].end());
	}
	
	bool Flag=false;
	
	for(int i=2;i<=n;i++){
		bool flag=true;
		
		for(int u:pos[i]){
			auto tmp=lower_bound(pos[i-1].begin(),pos[i-1].end(),u);
			if (tmp!=pos[i-1].end()&&(*tmp==u)&&i==lst[u]){
				flag=false;break;
			}
		}
		
		if (flag){
			Flag=true;
			swap(ans[i],ans[i-1]);
			break;
		}
	}
	
	if (Flag){
		printf("Yes\n");
		for(int i=1;i<=n;i++)
			printf("%d%c",ans[i],(i==n?'\n':' '));
	}
	else printf("No\n");
	
	return Flag;
}

int main(){
	int T=read();
	while (T--) OZDY();
	
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...