错排问题:不能错这么多

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 eq 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) 的子问题并合并答案。递推式为:

[egin{cases} mathrm{dp}[1]=1 \ mathrm{dp}[2]=2 \ mathrm{dp}[i]=mathrm{dp}[i-2]cdot(n-1)+mathrm{dp}[i-1] & (2<ile 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) 的子问题

[egin{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<ile n) end{cases} ]

(mathrm{step}=4) 则有

[egin{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),可能有(未证,猜想有):

[egin{cases} mathrm{dp}[i]=i! & (ile mathrm{step}) \ mathrm{dp}[i]=sumlimits_{p=i-mathrm{step}}^{i-2}(mathrm{dp}[p]cdotprodlimits_{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("
");
        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
",i,dp[i],foo[i],dp[i]==foo[i]?"YES":"NO");
    }
    return 0;
}

Question

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

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

* 最佳答案:我不知道

无特别声明的情况下,本文为原创文章,允许转载,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
在声明禁止转载的情况下,请勿转载;若本文章为转载的文章,版权归原作者所有。
如果您觉得本文写得好,请点击下方的推荐按钮~若您有任何建议和指正,请在下方留言,对于您的指正将不胜感激。
原文地址:https://www.cnblogs.com/ksyx/p/derangement-plus.html