1. 程式人生 > >[HEOI2014]平衡(整數劃分數)

[HEOI2014]平衡(整數劃分數)

下課了,露露、花花和萱萱在課桌上用正三稜柱教具和尺子擺起了一個“蹺蹺板”。

這個“蹺蹺板”的結構是這樣的:底部是一個側面平行於地平面的正三稜柱教具,上面 擺著一個尺子,尺子上擺著若干個相同的橡皮。尺子有 2n + 1 條等距的刻度線,第 n + 1 條 刻度線恰好在尺子的中心,且與正三稜柱的不在課桌上的稜完全重合。

露露發現這個“蹺蹺板”是不平衡的(尺子不平行於地平面)。於是,她又在尺子上放 了幾個橡皮,並移動了一些橡皮的位置,使得尺子的 2n + 1 條刻度線上都恰有一塊相同質 量的橡皮。“蹺蹺板”平衡了,露露感到很高興。

花花覺得這樣太沒有意思,於是從尺子上隨意拿走了 k 個橡皮。令她驚訝的事情發生了: 尺子依然保持著平衡! 萱萱是一個善於思考的孩子,她當然不對尺子依然保持平衡感到吃驚,因為這只是一個 偶然的事件罷了。令她感興趣的是,花花有多少種拿走 k 個橡皮的方法,使得尺子依然保 持平衡?當然,為了簡化問題,她不得不做一些犧牲——假設所有橡皮都是擁有相同質量的 質點。但即使是這樣,她也沒能計算出這個數目。放學後,她把這個問題交給了她的哥哥/ 姐姐——Hibarigasaki 學園學生會會長,也就是你。當然,由於這個問題的答案也許會過於 龐大,你只需要告訴她答案 mod p 的值。

Solution

非常好的一道題。

題目相當於在兩邊放k個數,使他們相等,我們可以跑一個整數劃分數dp。

但是這道題有一個限制是每個數是n以內的。

所以我們要在列舉超過n時減掉不合法方案數,dp[i-(n+1)][j-1]就是不合法方案。

最後列舉一邊放了多少個,算一下,注意討論中間放的情況。

Code

#include<iostream>
#include<cstdio>
#define R register
using namespace std;
long long dp[150009][15],ans,n,k,p,t;
int main()
{
    scanf(
"%lld",&t); for(int o=1;o<=t;++o) { scanf("%lld%lld%lld",&n,&k,&p); ans=0; dp[0][0]=1; for(R int i=1;i<=n*k;++i) for(R int j=1;j<=i&&j<=k;++j) { dp[i][j]=(dp[i-j][j-1]+dp[i-j][j])%p;
if(i>n)dp[i][j]=(dp[i][j]-dp[i-(n+1)][j-1]+p)%p; } for(R int j=0;j<=k;++j) for(R int i=0;i<=n*k;++i) { ans=(ans+dp[i][j]*dp[i][k-j])%p; if(j<k)ans=(ans+dp[i][j]*dp[i][k-j-1])%p; } printf("%lld\n",ans); } return 0; }