poj 2779 Mr. Young's Picture Permutations

来源:互联网 发布:淘宝客服忙不忙 编辑:程序博客网 时间:2024/05/01 11:07

浪费我好多时间啊,如果dp实力强的,可以用dp写,确实算是dp的好题,但是我很水,只能去找那个钩子公式,baidu、google都找了,结果只找到英文的原网站(不吐槽,我这种英语水平怎么可能看懂),最后终于看见一篇还可以的,大致的应用会了,大家如果问我证明,我也只能说sorry。

英文原网站:http://en.wikipedia.org/wiki/Young_tableau

题意:杨先生要给他的学生们拍照片,若第i行站了a[i]个人,则有a[1] ≥ a[2] ≥ ... ≥ a[n],所有的行都是靠左对齐的。并且,在同一行和同一列里面,从左到右或者从上到下身高都是递减的。现在所有学生的身高都不相同,学生数不超过30个,行数不超过5。你需要求出所有可能的排队方法的总数。

思路:别人说这种问题是钩子公式的模板问题。我来简单的说说钩子公式吧,把学生站队的地方看成一个地图,

最后的总数(sum)为 sum=n! /((H1)*(H2)*....*(Hn)),学生总数为n,对地图上的每个学生进行一个进行一个编号1~n,Hx表示第x个学生同一列(下面的)和同一排(右边的)的学生加上他自己的人数总和,这个编号是对结果无影响的,所以只需要算Hx就ok。

#include<cstdio>#include<cstring>#include<iostream>using namespace std;int gcd(int a,int b){    return  a%b==0?b:(gcd(b,a%b)) ;}int n,map[14][41],val[51],fact[41],sum;int main(void){    while(cin>>n,n)    {        sum = 0;        memset(map,0,sizeof(map));        for(int i=1;i<=n;++i)        {            int a;            scanf("%d",&a);            sum += a;            for(int j=1;j<=a;++j)            {                map[i][j] = 1;            }        }        int cou = 1;        for(int i=1;i<14;++i)        for(int j=1;j<41;++j)        if(map[i][j])        {          val[cou] = 1;          for(int k=i+1;k<14;++k)                val[cou] += map[k][j];          for(int k=j+1;k<41;++k)                val[cou] += map[i][k];          ++cou;        }        for(int i=1;i<=sum;++i)            fact[i] = i;        for(int i=1;i<=sum;++i)            for(int j=1;j<=sum;++j)        {            int tmp = gcd(fact[i],val[j]);            fact[i] /= tmp; val[j] /= tmp;        }        long long num = 1;        for(int i=1;i<=sum;++i)            num *= fact[i];        cout<<num<<endl;    }    return 0;}


原创粉丝点击