P3876 [TJOI2010] 数字序列
题意
要求构造一个序列,包含 \(0,1,2,3\),相邻的两个数不能是 00,11,22,33,02,20,23,32,13,31,并且有 \(m\) 个限制,每个限制给出一些位置,要求这些位置上的数两两不同,问有没有解。
\(n\le10^5,m\le5000\)。
思路
显然,当一个约束集合的大小 \(>4\) 时无解。
发现 \(3\) 旁边能放 \(0\),\(0\) 旁边能放 \(1,3\),\(1\) 旁边能放 \(0,2\),\(2\) 旁边能放 \(1\)。给数字重标号,那么问题变成了,判断是否有一个由 \(\set{1,2,3,4}\) 组成的序列,相邻两个元素相差 \(1\),有一些位置数不能相同。
把位置按照奇偶性分成两部分,令第一个数是 \(1\) 或 \(3\),那么奇数位置的数都是 \(1\) 或 \(3\),偶数位置的数都是 \(2\) 或 \(4\)。把每个约束拆成很多个二元的约束,用 \(2-sat\) 解决。一个约束对 \((u,v)(u<v)\),如果 \(v-u\) 是奇数,那么祂们肯定不一样,否则转换为一些推导关系。相邻的两个数之间也有推导关系。
代码
// Problem: P3876 [TJOI2010] 数字序列
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3876
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=100010;
int n,m,p[maxn],cnt_scc,sy[maxn*2];
vector<int>e[maxn*2],f[maxn*2],vt;
bool flag[maxn*2];
int id_1(int u){return u*2-1;}
int id_2(int u){return u*2;}
void edge_add(int u,int v){e[u].push_back(v),f[v].push_back(u);}
void dfs1(int u){
if(flag[u]) return ;flag[u]=1;
for(int v:f[u]) dfs1(v);
vt.push_back(u);
}
void dfs2(int u,int bh){
if(sy[u]) return ;sy[u]=bh;
for(int v:e[u]) dfs2(v,bh);
}
void qlt(){
memset(flag,0,sizeof(flag));
memset(sy,0,sizeof(sy));
cnt_scc=0;
for(int i=1;i<=n*2;i++) dfs1(i);
while(!vt.empty()) dfs2(vt.back(),++cnt_scc),vt.pop_back();
}
void solve(){
for(int i=1;i<=n*2;i++) e[i].clear(),f[i].clear();
read(n,m);
bool f=0;
for(int i=1;i<=m;i++){
int L;read(L);
for(int j=1;j<=L;j++) read(p[j]);
if(L>4){f=1;continue;}
for(int a=1;a<=L;a++) for(int b=a+1;b<=L;b++){
int u=p[a],v=p[b];
if((u&1)!=(v&1)) continue;
edge_add(id_1(u),id_2(v));
edge_add(id_2(u),id_1(v));
edge_add(id_1(v),id_2(u));
edge_add(id_2(v),id_1(u));
}
}
for(int i=1;i<n;i++){
edge_add(id_2(i),id_1(i+1));
edge_add(id_2(i+1),id_1(i));
}
if(f){write("No");return ;}
qlt();
for(int i=1;i<=n;i++) if(sy[id_1(i)]==sy[id_2(i)]){write("No");return ;}
write("Yes");
}
signed main(){
int T;read(T);
while(T--) solve(),write("\n");
return 0;
}

浙公网安备 33010602011771号