输入样例
1
30
5
1 1 1 1 1
3
3 2 1
4
5 3 3 1
5
6 5 4 3 2
2
15 15
0
输出样例
1
1
16
4158
141892608
9694845
这道题相对来说,我第一次感受到了压力吧,这道题我也看出来要是dfs一定百分百超时,要用dp做,用dp又不知道思路,无敌的yxc老师来了!!!!
https://www.acwing.com/video/397/
yxc老师yyds
讲的真很细
首先分几种情况:把每一排的最后一个数(最大的数插进去的点)类似于去除,然后加上这一形状的方案数,(就是这一形状的方案数),然后向前递归(直接从小到大就实现了),我自己脑子演示了一遍,这方法很好,但是我也有注意到要是上下两行相等的话不能去除,看到老师的代码,我就知道用if就可以解决问题。也学到了一个新的指针,干货很多呀
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=31;
LL f[N][N][N][N][N];
int s[6];
int main(void)
{
int n;
while(cin>>n,n)
{
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++) cin>>s[i];
memset(f,0,sizeof(f));
f[0][0][0][0][0]=1;//因为求的是方案,要以此往后递推
for(int a=0;a<=s[1];a++)
for(int b=0;b<=s[2];b++)
for(int c=0;c<=s[3];c++)
for(int d=0;d<=s[4];d++)
for(int e=0;e<=s[5];e++)
{
LL &v=f[a][b][c][d][e];//用指针操作减少了写代码的麻烦
//每一行都要判断是否为0,并且是否减去这个还满足这个结构
if(a&&a-1>=b) v+=f[a-1][b][c][d][e];
if(b&&b-1>=c) v+=f[a][b-1][c][d][e];
if(c&&c-1>=d) v+=f[a][b][c-1][d][e];
if(d&&d-1>=e) v+=f[a][b][c][d-1][e];
if(e) v+=f[a][b][c][d][e-1];
}
cout<<f[s[1]][s[2]][s[3]][s[4]][s[5]]<<endl;
}
}
然后数据多而且大,时间看起来像超时的样子。