题解【CF863F Almost Permutation】


传送门。

$\texttt{Description}$

$n$ 个数,每个数都在 $1$ 至 $n$ 间。$m$ 个形如 $[l,r]$ 中的数不小于或不大于 $v$ 的限制。设 $cnt(i)$ 表示 $i$ 的出现次数,求 $\sum cnt_i^2$ 的最小值。

$1\le n\le 50$,$1\le m\le 100$。

$\texttt{Solution}$

发现数据范围这么小,那么我们可以暴力预处理出,序列中每一个 $a_i$ 可能取到的范围,设为 $[down_i,up_i]$。

然后考虑一个二分图模型。

左边是 $1$ 至 $n$,代表每一个位置,右边是 $1$ 至 $n$,代表序列中每一个位置上可能的值。

每一个位置上只能有一个数,所以我们连 $s\to i$,容量为 $0$,费用为 $1$。

然后对于每一个位置连向它能取到的区间即 $[down_i,up_i]$,流量为 $1$,费用为 $0$。

这些都是非常显然的。

但问题在于,如果我们右边的每一个数,向 $t$ 连一条容量为 $\infty$ 费用为 $1$ 的边(表示一个数可能被多个位置匹配,然后每一个位置都要有 $1$ 的贡献),最终需要求得是 $\sum cnt_i^2$,无法解决。

考虑右边一个数,最多被匹配的上限是 $n$,那么将这个点向 $t$ 连 $n$ 条边,第 $i$ 条边,容量为 $1$,费用为 $i^2-(i-1)^2$。

这是什么意思呢?

考虑它的匹配,容量都一样,那么我们 $\texttt{spfa}$ 在找增光路的时候肯定会找费用最小的几条。

当从第 $i$ 小的边,加入了第 $i+1$ 小的边时,$i^2$ 的那一项恰好被削掉,$(i-1)^2$ 的那一项又被前面的消掉,所以求和起来就是 $(i+1)^2$。

个人感觉像是构造的思想,十分巧妙。也许是一种 $\texttt{trick}$ 但我并不知道。

代码:

int main()
{
    n=read(),m=read();
    s=0,t=n<<1|1;
    for(register int i=1;i<=n;i++) down[i]=1,up[i]=n;
    for(register int i=1;i<=m;i++)
    {
        int opt=read(),l=read(),r=read(),v=read();
        if(opt==1) for(register int j=l;j<=r;j++) down[j]=Max(down[j],v);
        else for(register int j=l;j<=r;j++) up[j]=Min(up[j],v);
    } 
    for(register int i=1;i<=n;i++) if(down[i]>up[i])
    {
        puts("-1");
        return 0;
    }
    for(register int i=1;i<=n;i++)
        for(register int j=down[i];j<=up[i];j++)
            add_edge(i,j+n,1,0);
    for(register int i=1;i<=n;i++) add_edge(s,i,1,0);
    for(register int i=1;i<=n;i++)
        for(register int j=1;j<=n;j++)
            add_edge(i+n,t,1,(j<<1)-1);
    MCMF();
    return 0;
}

注意数组不要开小了。

$$\texttt{The End.by UF}$$