CF1503E 2-Coloring

彬彬冰激凌發表於2024-08-17

CF1503E 2-Coloring

cjx 組合強。

思路

觀察一下題目,不難發現只有當黃色形成如下的單峰時才合法。

染錯色了,將就一下

其中兩座峰的峰頂高度相加等於 \(m\),為了方便統計,我們欽定右邊的峰一定在左峰下方的行出現,最後答案乘以二就是最終方案。

發現對於每一邊是兩個最長不下降子序列拼在一起。

\(f[i][j]\) 為長度為 \(i\) 的最長不下降子序列,最高點高度為 \(j\) 的方案數。

再設 \(f'[i][j]\) 為長度為 \(i\) 的最長不下降子序列,僅有一個最高點為 \(j\) 的方案數。

答案就是

\[2\times \sum_{i=1}^n\sum_{j=i+1}^{n}\sum_{k=1}^{m-1} (f[i][k]\times f'[n-i+1][k])\times (f'[j][m-k]\times f[n-j+1][m-k]) \]

相當於列舉第一個峰在行 \(i\),第二個峰在行 \(j\),第一個峰高度為 \(k\)

變幻一下:

\[2\times \sum_{i=1}^n\sum_{k=1}^{m-1}(f[i][k]\times f'[n-i+1][k])\times \sum_{j=i+1}^{n} (f'[j][m-k]\times f[n-j+1][m-k]) \]

這樣給後一個和式做一個字尾和最佳化,即可把複雜度最佳化到 \(O(n^2)\) 級別。

當然有例外是這個樣子。

兩峰交在一起(必須保證在連續的行且峰頂高度相加大於 \(m\)),也是一種方案。

\[2\times \sum_{i=1}^n\sum_{x=1}^{m-1}\sum_{y=1}^{m-1} (f[i][x]\times \sum_{k=1}^{y-1} f[n-i][k])\times (f[n-i][y]\times\sum_{k=1}^{x-1}f[i][k]) \]

相當於列舉左邊的峰頂在行 \(i\),左峰高度為 \(x\),右峰高度為 \(y\),同時求和了峰過後的一段不下降子序列的方案。

\[2\times \sum_{i=1}^n\sum_{x=1}^{m-1} (f[i][x]\times\sum_{k=1}^{x-1}f[i][k] )\sum_{y=1}^{m-1} (f[n-i][y]\times\sum_{k=1}^{y-1} f[n-i][k]) \]

對於 \(\sum_{k=1}^{x-1}f[i][k]\)\(\sum_{k=1}^{y-1} f[n-i][k]\) 字首和最佳化。

然後預處理出所有的

\[f[n-i][y]\times\sum_{k=1}^{y-1} f[n-i][k] \]

再次字首和。

即可在 \(O(n^2)\) 的時間內求出上述和式。

對於 \(f\)\(f'\) 的轉移是容易的。

\[f[i][j]=\sum_{k=1}^j f[i-1][k] \]

\[f'[i][j]=\sum_{k=1}^{j-1} f[i-1][k] \]

初始值 \(f[0][0]=1\)

其實你看到這裡,已經可以使用 dp 做出本題了,但是如果你想進一步瞭解組合,請移步。

不難發現,我們每次的轉移都相當於求一次字首和,而 \(f[0][0]=1\)

所以有可以構造這樣的生成函式:

\[f[0]=1 \]

觀察 \(\sum_{i=0} x^i\) 的優雅性質,你會發現 \(1\times \sum_{i=0} x^i\) 相當於求一次字首和。

\((\sum_{i=0} x^i)^2\) 相當於求兩次字首和(\(x^i\) 的係數是第 \(i\) 項的求字首和後的值)。

\(f[0]\) 轉移到 \(f[1]\) 的過程相當於乘以 \(\sum_{i=0} x^i\)(一次字首和),所以有:

\[f[1][j]=[x^j](\sum_{k=0} x^k)^1 \]

推廣一下,每次 \(f[i]\)\(f[i+1]\) 的轉移都是乘以 \(\sum_{i=0} x^i\)(每轉移一次求一次字首和),所以有:

\[f[i][j]=[x^j](\sum_{k=0}x^k)^i \]

對於 \(\sum_{i=0} x^i\),的封閉形式為 \((1-x)^{-1}\) 有很多種方法求,這裡不再贅述。

所以有:

\[f[i][j]=[x^j](1-x)^{-i} \]

使用廣義二項式展開 \((1+(-x))^{-i}\),即可得到第 \(j\) 項的係數為:

\[\binom{-i}{j}=(-1)^j\binom{i+j-1}{j} \]

關於牛頓二項式係數,已經有完備的公式,本處直接套公式即可,故不再展開討論。

把係數乘上 \((-x)^j\),有

\[f[i][j]=\binom{i+j-1}{j} \]

從比較簡單的組合意義考慮,有 \(j\) 個球,有 \(i-1\) 個擋板,可以為空,兩個擋板之間的球數相當於相鄰兩項的差。

那麼有:

\[f[i][j]=\binom{i+j-1}{i-1}=\binom{i+j-1}{j} \]

在觀察一下 \(f'\) 求值的式子,你會發現 \(f'[i][j]=f[i][j-1]\)

所以其實你也求出 \(f'\) 的組合意義了。

相當於有 \(j\) 個球,\(i-1\) 個擋板,最後一個擋板至少擋一個球,那麼就可以投入 \(j-1\) 個球供所有擋板擋。

\[f'[i][j]=\binom{i+j-2}{j-1} \]

如果考慮生成函式的話,\(f'[i][j]\) 相當於較 \(f[i][j]\) 向後平移了一個位置,那麼可以寫成:

\[f'[i][j]=[x^{j-1}](1-x)^{-i} \]

\[f'[i][j]=[x^j](1-x)^{-i}x \]

於是你就可以 愉快 的 AC 本題了。

CODE

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define N 5000
#define mod 998244353

const int maxn=5e3+5;

ll n,m,ans;
ll fac[maxn],inv[maxn],f[maxn];

inline ll ksm(ll x,ll y)
{
    ll sum=1;
    for(;y;y/=2,x=x*x%mod) if(y&1) sum=sum*x%mod;
    return sum;
}
inline ll C(int n,int m)
{
    if(n<m||m<0) return 0;
    return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main()
{
    freopen("magic.in","r",stdin);
    freopen("magic.out","w",stdout);
    for(int i=fac[0]=1;i<=N;i++) fac[i]=fac[i-1]*i%mod;
    inv[N]=ksm(fac[N],mod-2);
    for(int i=N-1;~i;i--) inv[i]=inv[i+1]*(i+1)%mod;
    scanf("%lld%lld",&n,&m);
    for(int h=1;h<n;h++)
    {
        for(int j=m;j>=2;j--)
        {
            f[j]=(1LL*f[j+1]+1LL*C(j+n-h-2,n-h-1)*C(m-j+n-h,n-h)%mod)%mod;
        }
        for(int i=m-1;i>=1;i--)
        {
            ans = (1LL*ans+1LL*C(i+h-1,h)*C(m-i+1+h-2,h-1)%mod*f[i+1]%mod)%mod;
        }
    }
    memset(f,0,sizeof(f));
    for(int x=1;x<=m;x++)
    {
        for(int j=n-1;j>=1;j--)
        {
            f[j]=(1LL*f[j+1]+1LL*C(m-x+n-j-1,n-j-1)*C(m-x+j-1,j)%mod)%mod;
        }
        for(int i=1;i<n;i++)
        {
            ans=(1LL*ans+1LL*C(x+i-1,i)*C(x+n-i-1,n-i-1)%mod*f[n-i+1]%mod)%mod;
        }
    }
    printf("%lld\n",ans*2%mod);
}