暑期的训练发现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; }
原文:https://www.cnblogs.com/ckr1225/p/9451974.html