
思路1:暴搜–>骗分 //由于过于SB 本人不做演示
思路2:DP
设f[i][j]为用前i个数摆j盆且以i结尾的所有可能性
则可以发现:当第k~j盆摆放i时则可能的方案数为f[i-1][k-1] //k为1~j中的某一个位置
而k可以为1~j中的任何一个
则f[i][j]=第1行第j-a[i]列到第i-1行第j-1列这个矩阵的和
你们认为这就完了么??? 不当然不!!!
举个栗子:
输入:
3 4
3 2 2
模拟f数组:
1 2 3 4 第j列
1 1 1 1 _
2 1 2 2 2
3 1 3 5 6
第
i
行
以第3行第2列为例
f[3][2]=f[1][1]+f[2][1]=1+1=2 ???
但事实上却等于3 why???
我们列一下:
当第2盆摆3时,则有两种可能: (1,3),(2,3)
当第一种和第二种都摆3时,则有一种可能: (3,3)
但当第一种和第二种都摆3时,我们却未算进去
所以:
if (a[i]>=j) f[i][j]++;
so…
代码:
const int N=110,mod=1000007;
int ans,n,m,a[N],f[N][N];
int find (int x,int y)
{
int ans(0);
for (int i=1;i<=x-1;i++) for (int j=y-a[x];j<=y-1;j++) ans+=f[i][j],ans%=mod;
return ans%mod;
}
int main ()
{
scanf ("%d %d",&n,&m);
for (int i=1;i<=n;i++) scanf ("%d",&a[i]);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
f[i][j]=find (i,j);
if (a[i]>=j) f[i][j]=(f[i][j]+1)%mod;
//printf ("%d ",f[i][j]);
}
//printf ("\n");
}
for (int i=1;i<=n;i++) ans=(ans+f[i][m])%mod;
printf ("%d",ans); //输出为f[1][m]~f[n][m]的和
return 0;
}
但看一下时间复杂度:O(N2 *M2 )=108 勉强能过
但我们再看看:

本文探讨了一种使用动态规划和二维前缀和优化解决排列组合问题的方法,通过举例和详细解释代码实现过程,阐述了如何在时间复杂度较高的情况下进行优化。文章特别指出在计算过程中可能出现的重复计数问题,并提供了修正策略。
550

被折叠的 条评论
为什么被折叠?



