错排问题:不能错这么多

Background

P6174 这篇错排推导非常有趣,然后里面有个 point 是当想要把 \(n\) 号球放进 \(k\) 号箱子的时候,分成两种情况讨论:\(n\) 号箱子里装的或者不是 \(k\) 号球。在这里,错排求的方案数是 限制某个箱子不能装某个球,求可行的把球放进箱子,每个箱子里装的是一个的方案数。那么,\(n\) 号箱子装 \(k\) 号球,\(k\) 号箱子装 \(n\) 号球这个相互放 fact 非常的有意思,通过这个玩法我们将子问题 \(D_n\) 缩小到了子问题 \(D_{n-2}\)

令最后盒子 \(i\) 中装的球为 \(\mathrm{box}[i]\),在原版的问题中显然不合法的条件为存在 \(\mathrm{box}[i]=i\),即箱子 \(i\) 不能装 \(i\) 号球。那么如果拓展一下问题,把它反转过来,现在我们求正确的放置方案有多少种。显然,一种:对于 \(\forall i \in [1,n]\)\(\mathrm{box[i]}=i\)。那我们放宽一点要求,\(\mathrm{box}[\mathrm{box}[i]]=i\),即沿着盒子里球的编号去找另一个盒子里的球找到了,也可以接受,有多少种方案?如果 \(\mathrm{box}[\mathrm{box}[\mathrm{box}[i]]]=i\) 也可以接受呢?如果 \(\mathrm{box}[\mathrm{box}[\mathrm{box}[\mathrm{box}[i]]]]\) 也可以接受呢?令 \(\mathrm{box}^\mathrm{step}[i]\) 表示访问多少层 \(\mathrm{box}\),如上述分别为 \(\mathrm{step}=\{1,~2,~3,~4\}\),如果 \(\forall i \in [1,\mathrm{step}]\)\(\mathrm{box}^\mathrm{step}[i]\) 都可以接受呢?

Solution

这个问题起点在于缩小子问题的这个过程:当然我们考虑局部合法的情况时,首先,显然,把 \(k\) 球放入箱子 \(k\) 是一个 \(\mathrm{step}=1\) 的情形;而当我们选择球 \(k\) 和另一个箱子 \(p~(k\neq p)\) 时,如果 \(k\) 球放入了 \(p\)\(p\) 球放入了 \(k\),显然就成功构造了一个 \(\mathrm{step}=2\) 的情形。那么可接受的方案有多少种呢?\(n=1\) 时不存在 \(\mathrm{step}=2\) 而必定 \(1\) 号球入 \(1\) 号箱子,一种。\(n=2\)\(1,2\)\(2,1\) 都可以接受,分别是 \(\mathrm{step}\)\(1\)\(2\) 的情形,两种。\(n=3\) 呢?选一个球,然后再选另一个球(\(n-1\) 种选法),这两个球交错插入对方的箱子,此时两个箱子里的球都可以以 \(\mathrm{step}=2\) 被接受,问题变成剩下一个箱子求方案数;又或是这个球插入自己的箱子,这个球以 \(\mathrm{step}=1\) 被接受,求剩下两个箱子的方案数。这样分解问题的一个原因是,当一个大小不超过 \(\mathrm{step}\) 的箱子集合 \(S\) 里的球的集合 \(S'=S\) 时,\(S\) 中的任意一个箱子总能在 \(S\) 中找到和自己编号一致的球,而 \(S\) 外的任意一个箱子不会找到 \(S\) 中的箱子,所以我们可以 drop 掉这几个箱子和球,求解子问题。若设 \(\mathrm{dp}[i]\) 表示剩下 \(n\) 个球(箱子)时的方案数,即有 \(\mathrm{dp}[3]=\mathrm{dp}[3-2]\cdot (3-1)+\mathrm{dp}[3-1]=4\) 种。此时能发现,我们总能将球数为 \(n\) 的问题分解为 \(n'=n-2\)\(n'=n-1\) 的子问题并合并答案。递推式为:

\[\begin{cases} \mathrm{dp}[1]=1 \\ \mathrm{dp}[2]=2 \\ \mathrm{dp}[i]=\mathrm{dp}[i-2]\cdot(n-1)+\mathrm{dp}[i-1] & (2<i\le n) \end{cases} \]

\(\mathrm{step}=3\) 呢?此时,\(\mathrm{step}=2\) 的基础之上,我们选择三个箱子 \(p, q, r\)\((n-1)\cdot (n-2)\) 个选法),使得 \(\mathrm{box}[p]=q, \mathrm{box}[q]=r, \mathrm{box}[r]=p\),此时多分解出一个 \(n'=n-3\) 的子问题

\[\begin{cases} \mathrm{dp}[1]=1 \\ \mathrm{dp}[2]=2 \\ \mathrm{dp}[3]=6 \\ \mathrm{dp}[i]=\mathrm{dp}[i-3]\cdot(n-1)(n-2)+\mathrm{dp}[i-2]\cdot(n-1)+\mathrm{dp}[i-1] & (3<i\le n) \end{cases} \]

\(\mathrm{step}=4\) 则有

\[\begin{cases} \mathrm{dp}[1]=1 \\ \mathrm{dp}[2]=2 \\ \mathrm{dp}[3]=6 \\ \mathrm{dp}[4]=24 \\ \small{\mathrm{dp}[i]=\mathrm{dp}[i-4]\cdot(n-1)(n-2)(n-3)+\mathrm{dp}[i-3]\cdot(n-1)(n-2)+\mathrm{dp}[i-2]\cdot(n-1)+\mathrm{dp}[i-1]} & \small{(4< i \le n)} \end{cases} \]

对于任意 \(1<\mathrm{step}\le n,\mathrm{step}\in Z\),可能有(未证,猜想有):

\[\begin{cases} \mathrm{dp}[i]=i! & (i\le \mathrm{step}) \\ \mathrm{dp}[i]=\sum\limits_{p=i-\mathrm{step}}^{i-2}(\mathrm{dp}[p]\cdot\prod\limits_{q=n-(i-p-1)}^{n-1}q)+\mathrm{dp}[i-1] & (i>\mathrm{step}) \end{cases} \]

Code

写得非常暴力的一个版本,有空再改,包含了对拍和求解

#include <cstdio>
int box[15],ans=0,tot=0;bool used[15];
int n, foo[15], dp[15];
void search(int now){
    if(now>n) {
        tot++;
        for(int i=1;i<=n;i++)
            if(!(box[i]==i || box[box[i]]==i || box[box[box[i]]]==i || box[box[box[box[i]]]]==i)) return;
        ans++;
        for(int i=1;i<=n;i++)
            printf("%d ",box[i]);
        printf("\n");
        return;
    }
    for(int i=1;i<=n;i++) 
    if(!used[i])
    {
        box[now]=i;
        used[i]=1;
        search(now+1);
        used[i]=0;
    }
}
int main() {
    for(int i=1;i<=10;i++) {
        ans = 0; tot=0;
        n=i;
        search(1);
        foo[i]=ans;
    }
    dp[1]=1;dp[2]=2;dp[3]=6;dp[4]=24;
    for(int i=5;i<=10;i++) {
        dp[i]=dp[i-4]*(i-3)*(i-2)*(i-1)+dp[i-3]*(i-1)*(i-2)+dp[i-2]*(i-1)+dp[i-1];
        printf("%d %d %d %s\n",i,dp[i],foo[i],dp[i]==foo[i]?"YES":"NO");
    }
    return 0;
}

Question

\(\mathrm{step}\) 起点可以选择吗?可以中间少几个吗?即,这几个 \(\mathrm{step}\) 不合法的情况下能算吗:

  • \(2,3,4\)
  • \(1,2,4\)

* 最佳答案:我不知道

posted @ 2021-09-29 07:50  酷暑一夏1  阅读(101)  评论(0编辑  收藏  举报