poj2279——Mr. Young's Picture Permutations


Description

Mr. Young wishes to take a picture of his class. The students will stand in rows with each row no longer than the row behind it and the left ends of the rows aligned. For instance, 12 students could be arranged in rows (from back to front) of 5, 3, 3 and 1 students.
X X X X X

X X X
X X X
X

In addition, Mr. Young wants the students in each row arranged so that heights decrease from left to right. Also, student heights should decrease from the back to the front. Thinking about it, Mr. Young sees that for the 12-student example, there are at least two ways to arrange the students (with 1 as the tallest etc.):
 1  2  3  4  5     1  5  8 11 12

6 7 8 2 6 9
9 10 11 3 7 10
12 4

Mr. Young wonders how many different arrangements of the students there might be for a given arrangement of rows. He tries counting by hand starting with rows of 3, 2 and 1 and counts 16 arrangements:
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

Mr. Young sees that counting by hand is not going to be very effective for any reasonable number of students so he asks you to help out by writing a computer program to determine the number of different arrangements of students for a given set of rows.

Input

The input for each problem instance will consist of two lines. The first line gives the number of rows, k, as a decimal integer. The second line contains the lengths of the rows from back to front (n1, n2,..., nk) as decimal integers separated by a single space. The problem set ends with a line with a row count of 0. There will never be more than 5 rows and the total number of students, N, (sum of the row lengths) will be at most 30.

Output

The output for each problem instance shall be the number of arrangements of the N students into the given rows so that the heights decrease along each row from left to right and along each column from back to front as a decimal integer. (Assume all heights are distinct.) The result of each problem instance should be on a separate line. The input data will be chosen so that the result will always fit in an unsigned 32 bit integer.

Sample 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

Sample Output

1
1
16
4158
141892608
9694845

Solution:

本題是lyd神犇的進階指南上的DP題,狀態轉移方程看懂了,但是看似簡單去實現有點復雜啊,於是取搜羅本題的勾長公式的解法。

 

楊表由有限的方格組成。

 

對於一個正整數,給定一個整數分拆λ(10=1+4+5),則對應一個楊表(注意這是一個遞降的過程,也就是說下面一行的方格數要大於等於上一行的方格數)。

 

 技術分享

 

一個(1,4,5)分拆表示的楊表

 

楊表與整數分拆λ一一對應。

 

給定一個楊表,一共有n個方格。那么把1到n這n個數字填到這個楊表中,使得每行從左到右都是遞增的,每列從下到上也是遞增的。如圖

 

技術分享 

 

一個楊表的表示

 

【勾長】對於楊表中的一個方格v,其勾長hook(v)等於同行右邊的方格數加上同列上面的方格數,再加上1(也就是他自己)。

 

【勾長公式】用表示楊表個數,則

 

 技術分享

 

對於分拆10 = 5 + 4 + 1 的應的楊表. 因此共有

 

技術分享種方法。

 

公式題。求出同行右邊的方格數+同列上面的方格數+1。唯一注意的地方是最后除的時候要防止溢出。

 

轉載:

 這個題嘛,標准做法是線性DP。

 f[a1,a2,a3,a4,a5]表示每排從左起占了a1,a2,a3,a4,a5個人的方案數,f[0,0,0,0,0]=1。

 轉移方程為:當a1<N1,f[a1+1,a2,a3,a4,a5]+=f[a1,a2,a3,a4,a5],其余同理。

 上面是lyd講的,本蒟蒻覺得有點錯,但說不清哪兒有問題(也可能本身沒問題),路過的dalao幫看一看,謝告知。

 那么簡單做法就是:先去了解一下楊氏矩形和勾長公式,然后直接用公式做。我這種蒟蒻就選了這種方法……

楊氏矩陣定義(需滿足的條件/特征):

(1)若格子(i,j),則該格子的右邊和上邊一定沒有元素;

(2)若格子(i,j)有元素data[i][j],則該格子右邊和上邊相鄰的格子要么沒有元素,要么有比data[i][j]大的元素。

 顯然有同已寫元素組成的楊氏矩陣不唯一,1~n組成楊氏矩陣的個數可以寫出:

F[1]=1,F[2]=2,F[n]=F[n-1]+(n-1)*F[n-2] (n>2)。

 鈎子長度的定義:該格子右邊的格子數和它上邊的格子數之和;

 鈎子公式:對於給定形狀,不同的楊氏矩陣的個數為(n!/(每個格子的鈎子長度加1的積))。

 知道了這些再做這個題就很方便了……

 

代碼:

 

#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
ll n,cnt,x,y,tmp,num[40],sum[5200];
il ll gcd(int a,int b){return b?gcd(b,a%b):a;}
int main()
{
    while(scanf("%lld",&n)&&n){
        memset(sum,0,sizeof(sum));
        cnt=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++){
                cnt++;
                for(int k=i+1;k<=n;k++){
                    if(num[k]>=j)sum[cnt]++;
                    else break;
                }
                sum[cnt]+=num[i]-j+1;
            }
        for(int i=1;i<=cnt;i++){
            x*=i;y*=sum[i];
            tmp=gcd(x,y);
            x/=tmp;y/=tmp;
        }
        printf("%lld\n",x/y);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM