peiwenjun's blog 没有知识的荒原

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;
}

posted on 2022-06-13 13:51  peiwenjun  阅读(8)  评论(0)    收藏  举报

导航