题目链接:poj 2279
这个题目 有两种做法 dp 或者是 杨氏矩阵+勾长公式
首先是dp做法(参考lyd的书) 这有个小技巧 就是 31的5次方会爆内存 所以我们得开个可变的数组 就是 先把那5维的大小输入 在创建数组 这样可以节省很多空间 另外像这种可变数组是不能全局声明的
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int N[5];
int main(){
int k;
while(scanf("%d",&k)&&k){
memset(N,0,sizeof(N));
for(int i = 0; i < k; i++) scanf("%d",&N[i]);
ll dp[N[0]+3][N[1]+3][N[2]+3][N[3]+3][N[4]+3];
memset(dp,0,sizeof(dp));
dp[0][0][0][0][0]=1;
for(int i = 0; i <= N[0]; i++){
for(int j = 0; j <= N[1]; j++){
for(int x = 0; x <= N[2]; x++){
for(int y = 0; y <= N[3]; y++){
for(int p = 0; p <= N[4]; p++){
ll num = dp[i][j][x][y][p];
if(i<N[0])dp[i+1][j][x][y][p]+=num;
if(j<N[1]&&j<i) dp[i][j+1][x][y][p]+=num;
if(x<N[2]&&x<j) dp[i][j][x+1][y][p]+=num;
if(y<N[3]&&y<x) dp[i][j][x][y+1][p]+=num;
if(p<N[4]&&p<y) dp[i][j][x][y][p+1]+=num;
}
}
}
}
}
printf("%lld\n",dp[N[0]][N[1]][N[2]][N[3]][N[4]]);
}
return 0;
}
杨氏矩阵+勾子公式 看题目的样例 我们可以发现它是一个倒过来的杨氏矩阵
杨氏矩阵是啥咧
例如
7
4 5 6
1 2 3 4
这样的 每一行从左往右递增 每一列 从前往后递增的 就叫杨氏矩阵(不一定是个矩阵)
它是有计算公式的 , 在那之前还需要一个定义 就是勾子长度:对于一个格子来说 勾子长度是其右边的格子数目+其上方的各自数目+1(自己)
然后由勾长公式可以得到 满足这样的形状的杨式矩阵个数
其中n是格子数目
是i这个格子的勾子长度 那我们算一下每个 格子的勾子长度 在用公式求一下这题就行了 注意溢出的问题
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
ll n,cnt,x,y,tmp,num[40],sum[50];
int main()
{
while(scanf("%lld",&n)&&n){
memset(sum,0,sizeof(sum));
tot=0,x=1,y=1;
for(int i=1;i<=n;i++)scanf("%lld",&num[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=num[i];j++){
++tot;
for(int k=i+1;k<=n;k++){
if(num[k]>=j)sum[cnt]++; //向上找格子数
else break;
}
sum[tot]+=num[i]-j+1; //右边包括自己的格子数
}
for(int i=1;i<=tot;i++){
x*=i;y*=sum[i];
tmp=__gcd(x,y);
x/=tmp;y/=tmp;//除gcd防止溢出
}
printf("%lld\n",x/y);
}
return 0;
}