题意简述
给你n个数字串,刚开始每个数字的优先级为2,你要把某些数字的优先级设为1,然后使得得这些串不降,就是后面一个串要大于等于前面一个串,这个判断大小就是按位比较,先比较优先级,然后比较大小。
做法
为了方便叙述,我们把优先级为1的叫做大写,优先级为2的叫做小写。
我们把每个串i和他前面一个串i-1比较,找到第一个不相同的位置j,分类讨论一波
1.如果
,说明如果a[i][j]是大写,那么a[i-1][j]是大写,所以从a[i][j]向a[i-1][j]连一条边。
2.如果
,说明a[i-1][j]必须是大写,a[i][j]必须是小写,所以S向a[i-1][j]连边,a[i][j]向T连边。
还要注意一点,如果i这个串是i-1这个串的前缀,肯定无解,这个可以直接判掉
遍历完所有边之后,我们得到了一张图,然后我们从S开始BFS,能够走到的点都必须是大写。
如果能走到T,说明无解,这是显然的。
那么最后我们只要把所有S能遍历到的点输出来就行了。
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
#define LL long long
#define INF (2139062143)
#define N (100001)
using namespace std;
int n,m,x,S,T,cnt,tot,h,t;
int len[N],head[N],son[N<<3],nxt[N<<3],ans[N],q[N<<3];
bool vis[N];
vector <int> a[N];
template <typename T> void read(T&t) {
t=0;
bool fl=true;
char p=getchar();
while (!isdigit(p)) {
if (p=='-') fl=false;
p=getchar();
}
do {
(t*=10)+=p-48;p=getchar();
}while (isdigit(p));
if (!fl) t=-t;
}
inline void add(int x,int y){
son[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
int main(){
read(n),read(m);
for (int i=1;i<=n;i++){
read(len[i]);
a[i].push_back(0);
for (int j=1;j<=len[i];j++){
read(x);
a[i].push_back(x);
}
}
S=m+1,T=m+2;
for (int i=2;i<=n;i++){
bool over=0;
for (int j=1;j<=min(len[i],len[i-1]);j++){
if (a[i][j]!=a[i-1][j]){
if (a[i-1][j]>a[i][j]){
add(S,a[i-1][j]);
add(a[i][j],T);
}
else{
add(a[i][j],a[i-1][j]);
}
over=1;
break;
}
}
if (!over){
if (len[i]<len[i-1]){
puts("No");
return 0;
}
}
}
h=t=0;
q[++t]=S;
while (h<t){
int u=q[++h];
for (int p=head[u];p;p=nxt[p]){
if (!vis[son[p]]){
vis[son[p]]=1;
q[++t]=son[p];
}
}
}
if (vis[T]){
puts("No");
}
else{
for (int i=1;i<=m;i++){
if (vis[i]) ans[++cnt]=i;
}
puts("Yes");
printf("%d\n",cnt);
for (int i=1;i<=cnt;i++) printf("%d ",ans[i]);
}
return 0;
}