大意: n个字符串, 每次操作选出一种字符全修改为大写, 求判断能否使n个字符串字典序非降.
建源点s, 汇点t, s与所有必须转大写的连边, 必须不转大写的与t连边.
#include <iostream> #include <algorithm> #include <math.h> #include <cstdio> #include <set> #include <map> #include <string> #include <vector> #include <string.h> #include <queue> #define PER(i,a,n) for(int i=n;i>=a;--i) #define REP(i,a,n) for(int i=a;i<=n;++i) #define hr putchar(' ') #define pb push_back #define mp make_pair #define mid (l+r>>1) #define lc (o<<1) #define rc (lc|1) #define FI first #define SE second using namespace std; typedef long long ll; typedef pair<int,int> pii; const int P = 1e9+7; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;} ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;} //head const int N = 4e5+10; int a[N], b[N], c[N], vis[N], f[N], n, m, k, t; vector<int> s[N], g[N]; void dfs(int x) { if (vis[x]) return; vis[x] = 1; for (int y:g[x]) dfs(y); } int main() { scanf("%d%d", &n, &m); REP(i,1,n) { scanf("%d", &t); while (t--) scanf("%d",&k),s[i].pb(k); } REP(i,1,n-1) { int pos = 0; for (; pos<s[i].size()&&pos<s[i+1].size()&&s[i][pos]==s[i+1][pos]; ++pos); if (pos==s[i].size()) continue; if (pos==s[i+1].size()) return puts("No"),0; if (s[i][pos]>s[i+1][pos]) { g[0].pb(s[i][pos]), g[s[i+1][pos]].pb(m+1); } else { g[s[i+1][pos]].pb(s[i][pos]); } } dfs(0); if (vis[m+1]) return puts("No"),0; puts("Yes"); int ans = 0; REP(i,1,m) ans+=vis[i]; printf("%d ", ans); REP(i,1,m) if (vis[i]) printf("%d ", i);hr; }