解题报告:洛谷 P6965 [NEERC 2016] Binary Code
这个黑色的
思路
注意到
于是考虑用什么结构能够优化掉枚举。
我们两个 01 字符串之间连边当且仅当一个是另一个的前缀,此处有两种解法:哈希和 Trie树,本题解介绍的是 Trie树 做法。
我们把每个字符串所有可能的情况插入一棵 Trie 中,在树中,两点连边的情况就是一个是另一个祖先。
但是直接暴力做容易被卡成
我们设
我们希望最后的图可以经过若干中转点相连。
之后为了让我们在各个节点间连边,我们用
这样我们就需要:
可以看看这张图:
其中
以上是前缀部分的统计,我们之后要统计被前缀的。
我们先递归搜索左儿子和右儿子。
之后这样连边:
之后我们反着遍历,因为我各层之间的连边是通过最后一个来连接的,所以需要从前往后连,就有。
这样建复杂度理论上线性的,他本质上是这样的:
我们在 Trie 上,对于不同节点间 只连一条 有向边(虽然最后结果上是无向的),同一节点不同串之间练成一条链。
之后在整张图上跑 tarjan 求强连通分量即可。
闲话
代码最开始 T 了,于是用了快读,结果发现是 cerr
没删导致的...
代码
#include<bits/stdc++.h>
using namespace std;
// #define int long long
#define Air
namespace io {
class In {
public:
template<typename T>
inline In &operator>>(T &x) {
x=0;
bool f=0;
char c=getchar();
while(c<'0'||c>'9')
f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
if(c=='.') {
c=getchar();
double dot=0.1;
while(c>='0'&&c<='9')
x+=(c-'0')*dot,dot*=0.1,c=getchar();
}
return (f?x=-x:x),*this;
}
inline In &operator>>(char &x) {
while(isspace(x=getchar()));
return *this;
}
inline In &operator>>(char *x) {
char c=getchar();
while(isspace(c)) c=getchar();
while(!isspace(c)&&~c) *(x++)=c,c=getchar();
return *x=0,*this;
}
inline In &operator>>(string &x) {
char c=getchar();
x.clear();
while(isspace(c)) c=getchar();
while(!isspace(c)&&~c) x.push_back(c),c=getchar();
return *this;
}
inline In &operator>>(In &in) {
return in;
}
};
class Out {
private:
char buf[35];
short dot=6,top=0;
public:
template<typename T>
inline Out &operator<<(T x) {
if(x<0) putchar('-'),x=-x;
do {
buf[++top]=x%10,x/=10;
} while(x);
while(top) putchar(buf[top--]|'0');
return *this;
}
inline Out &operator<<(char c) {
return putchar(c),*this;
}
inline Out &operator<<(string x) {
for(auto c:x) putchar(c);
return *this;
}
inline Out &operator<<(char *x) {
while(*x) putchar(*(x++));
return *this;
}
inline Out &operator<<(const char *x) {
while(*x) putchar(*(x++));
return *this;
}
inline Out &operator<<(double x) {
snprintf(buf,sizeof(buf),"%.*lf",dot,x);
return (*this)<<buf;
}
inline Out &operator<<(Out &out) {
return out;
}
inline Out &setdot(const int n) {
return dot=n,*this;
}
};
In fin;
Out fout;
inline Out &setdot(const int n,Out& out=fout) {
return fout.setdot(n),out;
}
inline In &getline(char *x,In& in=fin) {
char c=getchar();
while(!(c==' '||!isspace(c))) c=getchar();
while(c==' '||!isspace(c)) (*x++)=c,c=getchar();
return *x=0,in;
}
inline In &getline(string &x,In& in=fin) {
char c=getchar();
x.clear();
while(!(c==' '||!isspace(c))) c=getchar();
while(c==' '||!isspace(c)) x.push_back(c),c=getchar();
return in;
}
}
using namespace io;
int read(){
int x;
fin>>x;
return x;
}
const int N=5e6+10;
int n;
string s[N],t[N][2];
int a[2][N];
int tot=1;
int ch[N][2];
vector<int>ed[N];
vector<int>e[N];
int ep[N][2];
// namespace Trie{
void inst(int id,int *arr,int len){
int x=1;
// cerr<<id<<' '<<len<<endl;
for(int i=1;i<=len;i++){
int c=arr[i];
if(!ch[x][c]){
ch[x][c]=++tot;
}
x=ch[x][c];
}
ed[x].push_back(id);
}//Trie
// }
int np;
// int p[N][2];
void insert(int x,int y){
if(!x||!y)return;
e[x].push_back(y);
}
void build(int now,int fa){
int lst=ep[fa][0];
for(auto y:ed[now]){
++np;
insert(y,lst);
insert(np,lst);
insert(np,y^1);
lst=np;
}
ep[now][0]=lst;
int lc=ch[now][0],rc=ch[now][1];
lst=++np;
if(lc)build(lc,now),insert(lst,ep[lc][1]);
if(rc)build(rc,now),insert(lst,ep[rc][1]);
for(int i=ed[now].size()-1;i>=0;i--){
int y=ed[now][i];
++np;
insert(y,lst);
insert(np,lst);
insert(np,y^1);
lst=np;
}
ep[now][1]=lst;
}
// namespace get_scc{
int low[N];
int dfn[N];
bool vis[N];
int scc_cnt=0;
int tim=0;
int col[N];
stack<int>st;
void tarjan(int now){
low[now]=dfn[now]=++tim;
st.push(now);
vis[now]=1;
for(auto y:e[now]){
if(dfn[y]&&vis[y]){
low[now]=min(low[now],dfn[y]);
}
if(!dfn[y]){
tarjan(y);
low[now]=min(low[now],low[y]);
}
}
if(dfn[now]==low[now]){
scc_cnt++;
while(st.top()!=now){
int id=st.top();
st.pop();
vis[id]=0;
col[id]=scc_cnt;
// quan[idx]+=a[id];
}
// int id=st.top();
st.pop();
vis[now]=0;
col[now]=scc_cnt;
// quan[idx]+=a[now];
}
}
// }
// using namespace Trie;
signed main(){
#ifndef Air
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
n=read();
np=n*2+1;//new node
for(int i=1;i<=n;i++){
fin>>s[i];
t[i][0]=t[i][1]=s[i];
bool flag=0;
for(int j=0;j<s[i].size();j++){
if(s[i][j]=='?'){
a[0][j+1]=0;
a[1][j+1]=1;
t[i][0][j]='0';
t[i][1][j]='1';
flag=1;
}
else{
a[0][j+1]=s[i][j]-'0';
a[1][j+1]=s[i][j]-'0';
}
}
inst(i*2,a[0],s[i].size());
inst(i*2+1,a[1],s[i].size());
// for(int j=1;j<=s[i].size();j++){
// cout<<a[1][j]<<s[i].size();
// }
// cout<<endl;
if(!flag){
e[i*2].push_back(i*2+1);
}
}
build(1,0);
// using namespace get_scc;
// tarjan(1);
for(int i=1;i<=np;i++){
if(!dfn[i]){
// cerr<<i<<endl;
tarjan(i);
}
}
for(int i=1;i<=n;i++){
if(col[i*2]==col[i*2+1]){
puts("NO");
return 0;
}
}
puts("YES");
for(int i=1;i<=n;i++){
if(col[i*2]<col[i*2+1]){
// puts("NO");
fout<<t[i][0]<<'\n';
// return 0;
}
else{
fout<<t[i][1]<<'\n';
}
}
return 0;
}