返回顶部

传统题

题面

$\quad $ 我们记 \(F(x)\)\(x\) 为真的方案数,\(len\) 为序列最长连续相同子段长度。

$\quad $ 那么就有:

\[ans=\sum _{i=1}^{n}F(len=i)*i \]

$\quad $ 也就是:

\[\sum _{i=1}^{n}F(len>=i) \]

$\quad $ 这里可以画个图,发现结果形如三角形,即可得出上式。再改变一下形式:

\[ans=nm ^{n} -\sum _{i=1}^{n-1}F(len<=i) \]

$\quad $ 然后考虑如何求解 \(F(len<=i)\) ,我们枚举这个序列分为 \(j\) 个区间,这些区间中元素的颜色一致且相邻区间颜色不同。可以发现,这样覆盖了全部的情况。

$\quad $ 发现所有区间的长度都小于等于 \(i\) 比较难做,没有限制的直接插空即可解决,所以我们考虑容斥,枚举这 \(j\) 个区间里有 \(k\) 个是长度大于 \(i\) 的,然后对于每一个枚举出来的 \(k\) ,我们将这几个区间长度减去 \(i\) ,那么这个问题就可以拿插空做了。于是得出式子:

\[ans=nm ^{n}-\sum _{i=1}^{n-1}\sum _{j=1}^{n}m(m-1) ^{j-1}\sum _{k=0}^{j}(-1) ^{k} C _{j}^{k} C _{n-ik-1}^{j-1} \]

$\quad $ 我们更换枚举顺序:

\begin{aligned}
ans&=nm ^{n} -\sum _{i=1}^{n-1}\sum _{k=0}^{n}(-1) ^{k}m\sum _{j=k}^{n}(m-1) ^{j-1}C _{j}^{k} C _{n-ik-1}^{j-1}\\
&=nm ^{n} -\sum _{i=1}^{n-1}\sum _{k=0}^{n}(-1) ^{k}m(n-ik) ^{-1}\sum _{j=k}^{n}(m-1) ^{j-1}C _{j}^{k} C _{n-ik}^{j}j
\end{aligned}

$\quad $ 现在看最后那个和式的组合意义。

$\quad $ 我们在 \(n-ik\) 个数中先选出 \(j\) 个数,再在这 \(j\) 个数中选出 \(k\) 个数,然后在 \(j\) 中选出一个数(下文记作 \(x\) )不染色,并对剩下的 \(j-1\) 个数染色,(这里的染色就是确定每个元素的种类,并且每个数只有 \(m-1\) 种可能)。

$\quad $ 然后我们可以先选出这 \(k\) 个数,然后再选出 \(x\)(注意 \(x\) 可以在那 \(k\) 个数中),然后去找能够包含他们的、大小为 \(j\) 的集合,并对集合中剩下的元素染色。

$\quad $ 对于现已经选择的数之外的数,他可以是选或不选,如果选了就有 \(m-1\) 种可能,那么就可以直接看做是给这些数染色,不过这里的每个元素有 \(m\) 种可能。

$\quad $ 那么这个时候 \(x\) 的位置就很重要了,这里就分出两种情况, \(x\) 在选出的 \(k\) 个数里、\(x\) 不在那 \(k\) 个数里。

$\quad $ 当 \(x\) 在那 \(k\) 个数中时,答案就是 \(C _{k}^{1}(m-1) ^{k-1}m ^{n-ik}\) ,也就是先确定出 \(x\) 的可能,然后对剩下的 \(k-1\) 个元素染色,再对这 \(k\) 个数外的的元素染色。注意这两种元素的染色可能数并不相同,见上文。

$\quad $ 当 \(x\) 不在那 \(k\) 个数里时,答案就是 \(C _{n-ik}^{1}(m-1) ^{n-ik-1} m ^{k}\) 。原理和上一种情况一样。

$\quad $ 那么我们就得出了最终的答案:

\[ans=nm ^{n}-m\sum _{i=1}^{n-1}\sum _{k=0}^{\lfloor\frac{n}{i+1}\rfloor}(-1) ^{k}(n-ik) ^{-1}[k((m-1) ^{k-1}m ^{n-ik})+(n-ik-1)(m-1) ^{n-ik-1} m ^{k}] \]

点击查看代码
#define yhl 0 
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+10;
int n,m,p,ans,fmo[N],fm[N],fact[N],ny[N],iv[N];
inline int calc(int i,int k){return (k?k*fmo[k-1]%p*fm[n-i*k-k]%p:0+(n-i*k-k)?fmo[k]*(n-i*k-k)%p*fm[n-i*k-k-1]%p)%p:0;}
inline int qum(int a,int b){
    int ans=1;
    while(b){
        (b&1)&&(ans=ans*a%p);
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
inline int C(int n,int m){return fact[n]*ny[n-m]%p*ny[m]%p;}
signed main(){
    scanf("%lld%lld%lld",&n,&m,&p);
    fmo[yhl]=fm[yhl]=fact[yhl]=ny[yhl]=1;
    for(int i=1;i<=n;i++){
        fmo[i]=fmo[i-1]*(m-1)%p;
        fm[i]=fm[i-1]*m%p;
        fact[i]=fact[i-1]*i%p;
    }
    ny[n]=qum(fact[n],p-2);
    for(int i=n-1;i;i--)ny[i]=ny[i+1]*(i+1)%p;
    for(int i=1;i<=n;i++)iv[i]=fact[i-1]*ny[i]%p;
    for(int i=1;i<n;i++){
        for(int k=yhl;k<=n/(i+1);k++){
            ans=(ans+(-1*(k&1)+1*((k&1)^1))*iv[n-i*k]%p*C(n-i*k,k)%p*calc(i,k)%p+p)%p;
        }
    }
    ans=(n*qum(m,n)%p-m*ans%p+p)%p;
    printf("%lld",ans);
    return yhl;
}

后记

$\quad $ 开始推式子的时候看 \(C _{j}^{k} C _{n-ik}^{j}\) 不是很顺眼,然后就给它展开凑项变成了 \(C _{n-ik}^{k}C _{n-ik-k}^{j-k}\) ,然后发现这个东西是可以推广的,也就是:

\[C _{n}^{m}C _{q}^{n}=C _{q}^{m}C _{q-m}^{q-n} \]

$\quad $ 证明:

\[C _{n}^{m}C _{q}^{n}=\frac{n!}{m!(n-m)!}\frac{q!}{n!(q-n)!}=\frac{q!}{m!(q-m)!}\frac{(q-m)!}{(q-n)!(n-m)!}=C _{q}^{m}C _{q-m}^{q-n} \]

$\quad $ 然后以为自己发现了什么了不得的东西,但是一想自己没那么厉害,怎么可能发现了前人没发现的东西,搜了一下发现在《具体数学》里提及了。

posted @ 2024-10-14 21:38  无敌の暗黑魔王  阅读(106)  评论(24编辑  收藏  举报