CF875C 题解

CF875C

思路

显然,满足 Si1SiS_{i-1}\leq S_i 即可使整体升序。对于每个 Si1SiS_{i-1}\leq S_i,都需要满足一些限制,只要所有限制前后不矛盾,则输出是。

分析 Si1SiS_{i-1}\leq S_i。枚举位置 jj 为第一个两者不等的位置,有几种情况:

  • 不存在 jj。此时如果 lenSi1lenSilen_{S_{i-1}}\leq len_{S_i},则 Si1SiS_{i-1}\leq S_i,没有额外限制。否则 SiS_i 一定小于 Si1S_{i-1},无解。

  • Si1,jS_{i-1,j} 小于 Si,jS_{i,j},则 Si1S_{i-1} 暂时小于 SiS_i,满足条件。此时只要 Si,jS_{i,j} 不改,或 Si1,jS_{i-1,j}Si,jS_{i,j} 同时改即可。也就是说,Si,jS_{i,j} 如果改了,Si1,jS_{i-1,j} 必须改。

  • Si1,jS_{i-1,j} 大于 Si,jS_{i,j},则 Si1S_{i-1} 暂时大于 SiS_i,不满足条件。此时必须改 Si1,jS_{i-1,j}Si,jS_{i,j} 一定不能改。

由上分析,可以建图解决。

ss 表示一定改的起点,tt 表示一定不改的终点。

情况 11 没有额外要求。情况 22 要求改 Si,jS_{i,j} 必须改 Si1,jS_{i-1,j},即 Si,jS_{i,j}Si1,jS_{i-1,j} 连边。情况 33 要求改 Si1,jS_{i-1,j},不改 Si,jS_{i,j},即 ssSi,jS_{i,j} 连边,Si1,jS_{i-1,j}tt 连边。

ss 开始搜索,如果能走到 tt 则矛盾,否则能走到的点即为要改的点。

code

int n,m,ans;
int s,t,cur;
int a[2][maxn];
bool vis[maxn];
int head[maxn],tot;
struct nd{
	int nxt,to;
}e[maxn<<1];
void add(int u,int v){
	e[++tot]={head[u],v};
	head[u]=tot;
}
void dfs(int u){
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!vis[v]){
			dfs(v);
		}
	}
}

int T;
signed main(){
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	
	n=read();m=read();
	s=0;t=m+1;
	for(int i=1;i<=n;i++){
		a[cur][0]=read();
		for(int j=1;j<=a[cur][0];j++){
			a[cur][j]=read();
		}
		if(i!=1){
			for(int j=1;j<=min(a[cur^1][0],a[cur][0]);j++){
				if(a[cur^1][j]>a[cur][j]){
					add(s,a[cur^1][j]);
					add(a[cur][j],t);
					break;
				}
				if(a[cur^1][j]<a[cur][j]){
					add(a[cur][j],a[cur^1][j]);
					break;
				}
				if(j==min(a[cur^1][0],a[cur][0])&&a[cur^1][0]>a[cur][0]){
					printf("No\n");
					return 0;
				}
			}
			
		}
		cur^=1;
	}
	dfs(s);
	if(vis[t]){
		printf("No\n");
	}
	else{
		printf("Yes\n");
		for(int i=1;i<=m;i++)if(vis[i])++ans;
		printf("%lld\n",ans);
		for(int i=1;i<=m;i++)if(vis[i])printf("%lld ",i);
	}
}