CF1697F Too Many Constraints 题解
题目描述
\(T\) 组数据,构造一个长为 \(n\) 的序列 \(a\) ,满足 \(1\le a_1\le\cdots\le a_n\le k\) 和如下 \(m\) 个附加限制,每个限制属于以下 \(3\) 类之一:
- \(a_i\neq x\) 。
- \(a_i+a_j\le x\) 。
- \(a_i+a_j\ge x\) 。
任意给出一个合法的序列即可,无解输出 \(-1\) 。
数据范围
- \(1\le T\le 10^4,2\le n\le 2\cdot 10^4,0\le m\le 2\cdot 10^4,\sum n,\sum m\le 2\cdot 10^4\) 。
- \(2\le k\le 10\) 。
时间限制 \(\texttt{2s}\) ,空间限制 \(\texttt{512MB}\) 。
分析
第一眼看过去,好像是一个 k-SAT 问题。
接下来是一个建图常用 trick :将序列中每个位置拆成 \(k\) 个点, \(x_{i,j}\) 表示 \(a_i\ge j\) 是否成立。
至此我们把 k-SAT 问题转化成了 2-SAT 问题,接下来考虑如何建图。
记 \(x_{i,j,0/1}\) 表示图中 \(x_{i,j}=0/1\) 表示的点。
-
每个 \(a_i\) 自身的限制会连成两条链 \((x_{i,j,1}\to x_{i,j-1,1}),(x_{i,j-1,0}\to x_{i,j,0})\) 。
由于 \(a_i\ge 1\) 恒成立,连边 \(x_{i,1,0}\to x_{i,1,1}\) 。
-
由于 \(a_i\) 非严格递增,若 \(a_i\ge j\) 则 \(a_{i+1}\ge j\) ,连边 \((x_{i,j,1}\to x_{i+1,j,1}),(x_{i+1,j,0}\to x_{i,j,0})\) 。
-
对于第一类限制,若 \(a_i\ge x\) 则 \(a_i\ge x+1\) ,连边 \((x_{i,x,1}\to x_{i,x+1,1}),(x_{i,x+1,0}\to x_{i,x,0})\) 。
不过需要特判 \(x=k\) 的情况,此时 \(x+1\) 会越界,改为 \((x_{i,x,1}\to x_{i,x,0})\) 。
-
对于第二类限制,若 \(a_i\ge l\) 则 \(a_j\le x-l\) ,并且 \(a_j\le x-l\Leftrightarrow a_j\not\ge x-l+1\) ,连边 \((x_{i,l,1}\to x_{j,x-l+1,0}),(x_{j,x-l+1,1}\to x_{i,l,0})\) 。
但这不足以成为充分条件,还需保证 \(\max(a_i,a_j)\le x-1\) 。
对 \(\forall l\ge x\) ,连边 \((x_{i,l,1}\to x_{i,l,0}),(x_{j,l,1}\to x_{j,l,0})\) 。
-
对于第三类限制,若 \(a_i\le l\) 则 \(a_j\ge x-l\) ,并且 \(a_i\le l\Leftrightarrow a_j\not\ge l+1\) ,连边 \((x_{i,l+1,0}\to x_{j,x-l,1}),(x_{j,x-l,0}\to x_{i,l+1,1})\) 。
同理 \(\forall l\le x-k\) ,连边 \((x_{i,l,0}\to x_{i,l,1}),(x_{j,l,0}\to x_{j,l,1})\) 。
输出方案时,先求出每个 \(x_{i,j}\) 的值。显然每个 \(i\) 有一段前缀为 \(1\) ,找到这个分界点即可。
时间复杂度 \(\mathcal O((n+m)k)\) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5,maxm=2e6+5;
int i,j,k,m,n,t,x,cnt,flg,num,opt,sum,tot;
int head[maxn],to[maxm],nxt[maxm];
int id[20005][11][2],res[20005][11];
int dfn[maxn],low[maxn];
stack<int> st;
bool ins[maxn];
int bel[maxn];
void addedge(int u,int v)
{
assert(u!=0&&v!=0);
nxt[++tot]=head[u],to[tot]=v,head[u]=tot;
}
void tarjan(int u)
{
dfn[u]=low[u]=++cnt;
st.push(u),ins[u]=true;
for(int i=head[u];i!=0;i=nxt[i])
{
int v=to[i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
int v;
sum++;
do
{
v=st.top(),st.pop();
ins[v]=false,bel[v]=sum;
}while(v!=u);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k),num=tot=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
for(int l=0;l<=1;l++)
id[i][j][l]=++num;
for(int i=1;i<=num;i++) dfn[i]=low[i]=head[i]=0;
for(int i=1;i<=n;i++)
{
addedge(id[i][1][0],id[i][1][1]);
for(int j=2;j<=k;j++)
{
addedge(id[i][j][1],id[i][j-1][1]);
addedge(id[i][j-1][0],id[i][j][0]);
}
}
for(int i=1;i<=n-1;i++)
for(int j=1;j<=k;j++)
{
addedge(id[i][j][1],id[i+1][j][1]);
addedge(id[i+1][j][0],id[i][j][0]);
}
while(m--)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d",&i,&x);
if(x==k) addedge(id[i][x][1],id[i][x][0]);
else
{
addedge(id[i][x][1],id[i][x+1][1]);
addedge(id[i][x+1][0],id[i][x][0]);
}
}
if(opt==2)
{
scanf("%d%d%d",&i,&j,&x);
for(int l=max(1,x-k+1);l<=min(k,x);l++)
{
addedge(id[i][l][1],id[j][x-l+1][0]);
addedge(id[j][x-l+1][1],id[i][l][0]);
}
for(int l=x;l<=k;l++)
{
addedge(id[i][l][1],id[i][l][0]);
addedge(id[j][l][1],id[j][l][0]);
}
}
if(opt==3)
{
scanf("%d%d%d",&i,&j,&x);
for(int l=max(0,x-k);l<=min(k-1,x-1);l++)
{
addedge(id[i][l+1][0],id[j][x-l][1]);
addedge(id[j][x-l][0],id[i][l+1][1]);
}
for(int l=1;l<=x-k;l++)
{
addedge(id[i][l][0],id[i][l][1]);
addedge(id[j][l][0],id[j][l][1]);
}
}
}
memset(ins,0,sizeof(ins));
cnt=sum=0,flg=1;
while(!st.empty()) st.pop();
for(int i=1;i<=num;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
{
int x=id[i][j][0],y=id[i][j][1];
flg&=bel[x]!=bel[y];
res[i][j]=bel[y]<bel[x];
}
if(!flg)
{
printf("-1\n");
continue;
}
for(int i=1;i<=n;i++)
{
int j=1;
while(j<=k&&res[i][j]) j++;
printf("%d ",j-1);
}
putchar('\n');
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16370594.html
浙公网安备 33010602011771号