zoukankan      html  css  js  c++  java
  • CF875C National Property 题解

    Codeforces
    Luogu

    Description.

    给定一些字符串,你需要给他们确定大小写,使得字符串字典序递增。  

    Solution.

    首先很显然,递增只需要 \(n-1\) 对相邻字符串都满足 \(S_{i-1}<S_{i}\)
    那么我们比较相邻字符串,发现必定有一段两个字符串相同。
    我们分类讨论下一位:

    1. 下一位在第一个字符串中不存在——必定成立
    2. 下一位在第二个字符串中不存在——必定无解
    3. 下一位在两个字符串中都存在——比较复杂,是后文重点解决的问题。

    那么我们现在需要考虑如何计算第三类的答案。
    刚开始觉得好像只需要一个拓扑排序就好了,然后怒斥是大水题,然后发现自己假地很惨。
    没想到 2-sat 问题,应该是没想的很深
    如果想到了 2-sat,那这题就做完了。
    就考虑分类讨论:

    1. \(a<b\),那 \(a\) 取小写能推出 \(b\) 取小写,\(b\) 取大写能推出 \(a\) 取大写。
    2. \(a>b\),那只可能是 \(a\) 取大写,\(b\) 取小写。

    然后套上 2-sat 模板即可。

    Coding.

    点击查看垃圾代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }/*}}}*/
    struct edge{int to,nxt;}e[400005];int n,m,et,head[200005];
    int buf[200005],*a[100005],ln[100005],tt,st[200005],tp;
    int dfn[200005],dt,low[200005],cl[200005],ct;char v[200005];
    inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
    inline void add(int x,int y)
    {//x表示大写,x+m表示小写,x<y
    	if(x<y) adde(x+m,y+m),adde(y,x);
    	if(x>y) adde(x+m,x),adde(y,y+m);
    }
    inline void tarjan(int x)
    {
    	dfn[x]=low[x]=++dt,v[x]=1,st[++tp]=x;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(!dfn[e[i].to]) tarjan(e[i].to),low[x]=min(low[e[i].to],low[x]);
    		else if(v[e[i].to]) low[x]=min(dfn[e[i].to],low[x]);
    	if(dfn[x]==low[x]) {int y=++ct;do v[y=st[tp--]]=0,cl[y]=ct;while(y^x);}
    }
    int main()
    {
    	read(n),read(m),a[1]=buf;for(int i=1;i<=n;i++)
    	{
    		read(ln[i]),a[i+1]=a[i]+ln[i];
    		for(int j=1;j<=ln[i];j++) read(a[i][j]);
    	}
    	for(int i=2;i<=n;i++)
    	{
    		char fg=1;for(int j=1;j<=ln[i]&&j<=ln[i-1]&&fg;j++)
    			if(a[i][j]^a[i-1][j]) add(a[i-1][j],a[i][j]),fg=0;
    		if(fg&&ln[i]<ln[i-1]) return puts("No"),0;
    	}
    	for(int i=1;i<=m+m;i++) if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=m;i++) if(cl[i]==cl[i+m]) return puts("No"),0;
    	int cnt=0;puts("Yes");for(int i=1;i<=m;i++) if(cl[i]<cl[i+m]) cnt++;
    	printf("%d\n",cnt);for(int i=1;i<=m;i++) if(cl[i]<cl[i+m]) printf("%d ",i);
    	return putchar('\n'),0;
    }
    
  • 相关阅读:
    C/C++多文件之间的变量定义
    PKU POJ 2186 Popular Cows 强连通分量
    重载函数
    ZOJ 2763 Prison Break
    201357 训练赛总结
    hdu 4467 Graph 构造
    201356 训练赛总结
    201353 NEERC 2012, Eastern subregional contest
    2013512 CF 183 总结
    一道动态规划
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15012727.html
Copyright © 2011-2022 走看看