POJ2279(dp)

题目描述
杨先生希望为他的班级拍照。学生将排成一排,每行不超过它后面的行,行的左端对齐。例如,12名学生可以排成5,3,3和1名学生的行(从后到前)。 XXXXX
XXX
XXX
X.
此外,杨先生希望每排学生安排高度从左到右减少。此外,学生的身高应该从后面降到前面。考虑到这一点,杨先生认为,对于12个学生的例子,至少有两种方式来安排学生(1个作为最高等): 1 2 3 4 5 1 5 8 11 12
6 7 8 2 6 9
9 10 11 3 7 10
12 4
杨先生想知道对于给定的行排列,可能有多少不同的学生安排。他尝试用3,2和1行开始手工计数,并计算16种安排: 123 123 124 124 125 125 126 126 134 134 135 135 136 136 145 146
45 46 35 36 34 36 34 35 25 26 24 26 24 25 26 25
6 5 6 5 6 4 5 4 6 5 6 4 5 4 3 3
杨先生认为手工计数对任何合理数量的学生都不会非常有效,因此他要求您通过编写计算机程序来帮助确定给定行集的学生的不同安排的数量。
输入格式
每个问题实例的输入将包含两行。第一行给出行数k,作为十进制整数。第二行包含从后到前(n1,n2,…,nk)的行的长度,作为由单个空格分隔的十进制整数。问题集以行数为0结束。行数永远不会超过5行,学生总数N(行长度之和)最多为30。
输出格式
每个问题实例的输出应该是N个学生在给定行中的排列数,以便高度沿着每一行从左到右沿着每一列从后到前逐渐减小为十进制整数。(假设所有高度都是不同的。)每个问题实例的结果应该在一个单独的行上。将选择输入数据,以使结果始终适合无符号的32位整数。
样例数据
input
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
output
1
1
16
4158
141892608
9694845
数据规模与约定
时间限制:1s
空间限制:65536KB


很暴力的一道题
考虑从小到大添数
fa1,a2,a3,a4,a5fa1,a2,a3,a4,a5表示第一行放了a1a1个,第二行…..第五行放了a5a5
a1>=a2>=a3>=a4>=a5a1>=a2>=a3>=a4>=a5
每次在aiai添加时必须满足ai1>aiai−1>ai

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define min(i,j,k) min(min(i,j),k)
int n , k;
int N[6];
ll dp[31][31][31][31][31];
namespace fastIO{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror = 0;
    inline char nc(){
        static char buf[BUF_SIZE],*p1 = buf+BUF_SIZE, *pend = buf+BUF_SIZE;
        if(p1 == pend){
            p1 = buf; pend = buf+fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1){ IOerror = 1; return -1;}
        }
        return *p1++;
    }
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
    inline void read(int &x){
        bool sign = 0; char ch = nc(); x = 0;
        for(; blank(ch); ch = nc());
        if(IOerror)return;
        if(ch == '-') sign = 1, ch = nc();
        for(; ch >= '0' && ch <= '9'; ch = nc()) x = x*10+ch-'0';
        if(sign) x = -x;
    }
    inline void read(ll &x){
        bool sign = 0; char ch = nc(); x = 0;
        for(; blank(ch); ch = nc());
        if(IOerror) return;
        if(ch == '-') sign = 1, ch = nc();
        for(; ch >= '0' && ch <= '9'; ch = nc()) x = x*10+ch-'0';
        if(sign) x = -x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
void Dp()
{
    dp[0][0][0][0][0] = 1;
    rep(i,1,n)
        rep(a1,1,N[1])
            rep(a2,0,min(N[2],i-a1,a1))
                rep(a3,0,min(N[3],i-a1-a2,a2))
                    rep(a4,0,min(N[4],i-a1-a2-a3,a3))
                    {
                        int a5 = i-a1-a2-a3-a4;
                        if(a5 > a4) continue;
                        dp[a1][a2][a3][a4][a5] = 0;
                        if(a1 > a2) dp[a1][a2][a3][a4][a5] += dp[a1-1][a2][a3][a4][a5];
                        if(a2 > a3) dp[a1][a2][a3][a4][a5] += dp[a1][a2-1][a3][a4][a5];
                        if(a3 > a4) dp[a1][a2][a3][a4][a5] += dp[a1][a2][a3-1][a4][a5];
                        if(a4 > a5) dp[a1][a2][a3][a4][a5] += dp[a1][a2][a3][a4-1][a5];
                        if(a5 > 0) dp[a1][a2][a3][a4][a5] += dp[a1][a2][a3][a4][a5-1];
                    }
}
int main()
{
    while(1)
    {
        read(k);n = 0;
        if(k == 0) break;
        rep(i,1,k) read(N[i]),n+=N[i];
        rep(i,k+1,5) N[i] = 0;
        Dp();
        printf("%lld\n",dp[N[1]][N[2]][N[3]][N[4]][N[5]]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值