【题解】arc165_d Substring Comparison
arc165_d Substring Comparison
简要题意
给定整数 \(n,m\),以及 \(m\) 个四元组 \((a_i,b_i,c_i,d_i)\)。
判断是否存在一个长度为 \(n\) 的正整数序列 \(x\),满足 \(\forall i\in [1,m]\),\(x_{a_i}\sim x_{b_i}\) 组成的序列的字典序严格小于 \(x_{c_i}\sim x_{d_i}\) 组成的序列。
\(n,m\le 2\times 10^3\)。
题解
知识点:图论,强连通分量。
启发:
- 处理多元互相制约的问题考虑建出限制图。
\(n,m\le 2\times 10^3\),说明做法大概在 \(O(n^2)\) 左右。
初始时,建出一个图,将所有 \(a_i\) 向 \(c_i\) 连一条有向边,表示 \(x_{a_i}<x_{c_i}\)。
如果当前图中不存在大小 \(\ge 2\) 的强连通分量,那说明是满足条件的,直接输出 Yes,判断这个东西可以用 tarjan 算法。
否则说明存在环,为了解决这个矛盾,只好令该强连通分量里的点代表的 \(x_i\) 都相等,随即找到对应的 \(a_i\) 和 \(c_i\),既然这一位必须得相等了,那就让 \(a_i+1\) 和 \(c_i+1\) 不相等,于是令 \(a_i\leftarrow a_i+1,c_i\leftarrow c_i+1\),然后再重新建图判断。
需要注意的是,如果某次 \(a_i,c_i\) 自增 \(1\) 后使得 \(c_i>d_i\),说明 \(b_i-a_i+1\ge d_i-c_i+1\),即前者区间长度大于等于后者,且他们在后者那段有效前缀得满足完全相等,此时不可能使得前者字典序严格小于后者,故此时输出 No。
综上来看,本题不仅可以以两个区间为载体作出限制,更能直接钦定两个子序列作出限制,但显然前者更具有迷惑性。
最坏情况下时间复杂度为 \(O(n(n+m))\),跑了 \(n\) 次 tarjan。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 2025
// #define int long long
int n,m,a[N],b[N],c[N],d[N],cnt;
int st[N],tp,fa[N],dfn[N],low[N];
bitset<N>in;
vector<int>e[N];
bool ex;
inline int ask(int k){
if(fa[k]==k){
return k;
}
return fa[k]=ask(fa[k]);
}
inline bool mg(int x,int y){
int fx=ask(x),fy=ask(y);
if(fx==fy){
return 0;
}
fa[fx]=fy;
return 1;
}
inline void clr(){
tp=cnt=0;
rep(i,1,n){
e[i].clear();
dfn[i]=low[i]=0;
in[i]=0;
}
}
inline void tarjan(int k){
low[k]=dfn[k]=++cnt;
st[++tp]=k;
in[k]=1;
for(int x:e[k]){
if(!dfn[x]){
tarjan(x);
low[k]=min(low[k],low[x]);
}
else if(in[x]){
low[k]=min(low[k],dfn[x]);
}
}
if(low[k]!=dfn[k]){
return;
}
if(st[tp]!=k){
ex=1;
}
while(st[tp]!=k){
in[st[tp]]=0;
mg(k,st[tp]);
tp--;
}
in[k]=0;
tp--;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,m){
cin>>a[i]>>b[i]>>c[i]>>d[i];
}
rep(i,1,n){
fa[i]=i;
}
rep(i,1,n){
clr();
rep(j,1,m){
while(a[j]<=b[j]&&c[j]<=d[j]&&ask(a[j])==ask(c[j])){
a[j]++;
c[j]++;
}
if(c[j]>d[j]){
cout<<"No";
return 0;
}
if(a[j]<=b[j]){
e[ask(a[j])].pb(ask(c[j]));
}
}
ex=0;
rep(j,1,n){
if(!dfn[j]){
tarjan(j);
}
}
if(!ex){
break;
}
}
cout<<"Yes";
return 0;
}

浙公网安备 33010602011771号