HEOI2014 平衡

暑期的训练发现DP不行,万年写不对系列已经上线

这题其实类似dp问题中的整数划分问题

考虑用dp[i][j]表示分成了不同的i个数,和为j

考虑转移dp[i][j]=dp[i-1][j-i]+dp[i][j-i]

考虑意义,dp[i][j-i]表示给当前i组全部都加上1

dp[i-1][j-i]表示考虑加入一个1,为了防止没有重复的数,所以先给原来的i-1个数都加1

那如果当前dp[i][j]有些方案没有1呢?我们发现根本不会少算,它一定会在其他dp值里面算到

最后枚举一下两边分别删几个就行了

注意特判K=1和取0的情况即可

代码:

#include<bits/stdc++.h>
using namespace std;
int dp[15][100005],T,n,k,Mod;
int main(){
    scanf("%d",&T);
    while (T--){
        scanf("%d%d%d",&n,&k,&Mod);
        dp[0][0]=1;
        for (int i=1;i<=k;i++){
            for (int j=i;j<=n*k;j++){
                dp[i][j]=1ll*(dp[i-1][j-i]+dp[i][j-i])%Mod;
                if (j>n) dp[i][j]-=dp[i-1][j-n-1];
                if (dp[i][j]<0) dp[i][j]+=Mod;
            }
        }int ans=0;if(k==1){puts("1");continue;}
        for (int i=1;i<k;i++)
            for (int j=i;j<=n*k;j++)
                ans=1ll*(ans+1ll*dp[i][j]*dp[k-i][j]%Mod)%Mod;
        for (int i=1;i<k-1;i++)
            for (int j=i;j<=n*k;j++)
                ans=1ll*(ans+1ll*dp[i][j]*dp[k-1-i][j]%Mod)%Mod;
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-08-09 21:51  longint  阅读(128)  评论(0编辑  收藏  举报