思路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 勉强能过
但我们再看看: