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;
    }
    
  • 相关阅读:
    最大回文子串
    求数组中的最大连续子序列和
    如何在10亿数中找出前1000大的数
    给定一个字符串,最多删除一个字符,判断能够构成回文字符串
    HashMap(数组+链表+红黑树)、HashTable、TreeMap
    【转】jmeter如何设置登录接口只调用一次以及遇到的问题:cookie参数放在消息头headers里面
    Kafka命令行操作
    git上无法push代码解决办法
    【转】Jenkins集成Docker镜像实现自动发布
    awk命令总结
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15012727.html
Copyright © 2011-2022 走看看