HDU 6360 【Polya定理+DP】

HDU6360

 

Kaleidoscope

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 35    Accepted Submission(s): 24

Problem Description

John loves colorful things such as kaleidoscope. When he started to take advantage of Wolfram Alpha, a scientific computing tool, he fell in love with its current logo, a rhombic hexecontahedron, immediately.


Wolfram|Alpha Computational IntelligenceTM



The rhombic hexecontahedron is a beautiful polyhedron which has 60 congruent rhombic faces. A rhombic hexecontahedron can be constructed from a regular dodecahedron, by taking its vertices, its face centers and its edge centers and scaling them in or out from the body center to different extents. Also, a rhombic hexecontahedron can be constructed from a regular icosahedron, by appending three rhombuses to each of its faces such that each rhombus shares a vertex with it and every two rhombuses share an edge.

John wants to make some origami of rhombic hexecontahedron. Before getting started from scratch, he was wondering in how many different ways he can make origami of at most n types of colored paper. He has thought for a while and finally determined to leave this problem for you. Furthermore, he added some restriction such that a way of origami is counted if the number of faces colored by the i-th type of paper is at least ci (i=1,2,⋯,n). Of course, the answer might be so large, so you just need to tell him the answer modulo some integer p.

Two ways are considered as the same if and only if there exists a way of rotation that can transform one to another so that each corresponding face has the same color. Here is an example of origami after coloring.


Picture from Wolfram Mathworld



In addition, he thought you might need a plane expansion for better understanding, however, because the plane expansion of a rhombic hexecontahedron is quite unreadable, he left here a modified plane expansion of a regular dodecahedron to illustrate approximately. Hope this image will help you solve this problem.

 

 

Input

The first line contains one integer T, indicating the number of test cases.
The following lines describe all the test cases. For each test case:
The first line contains two space-separated integers n and p.
The second line contains n space-separated integers c1,c2,⋯,cn.
1≤T≤1000, 1≤n≤60, 1≤p<230, 0≤ci≤60 (i=1,2,⋯,n).
It is guaranteed that no more than 100 test cases satisfy n>5.

 

 

Output

For each test case, print the answer modulo p in one line.

 

 

Sample Input

 

5

2 1000000007

0 0

2 1000000007

1 0

2 1000000007

0 2

2 1000000007 1 1 5 1000000007 1 1 1 1 1

 

 

Sample Output

 

544393230

544393229

544393228

544393228

905148476

 

感觉这篇博客写的特别好 :https://blog.csdn.net/u013534123/article/details/81488475

 

题意:给定一个rhombic hexecontahedron(菱形六面体,??? 只有六个面  ),给n种颜色,让你求出满足每种颜色不少于c[i]次的涂色方案的种数。

分析:对于旋转置换过程,楼上那边博客写的很详细,就不在此赘述。对于一般的置换polya定理公式为:l=\frac{1}{|G|}\sum_{i=1}^{k} c^{m_i}

其中c为颜色的种类数,m_i为每种置换的循环节数。这里的c^{m_i}表示对于每种置换它的循环节只被染成一种颜色的方案数。所以此题对于每种颜色限制个数,就可以用DP求出在有限制的情况下每种置换的循环节只染成一种颜色的方案数。dp[i][j]表示前i种颜色去染前j个循环节的方案数。所以转移方程为:dp[i][j]=\sum_{k=c[i]}^{j}dp[i-1][j-k]*C_j^k  c

 

 

#include<bits/stdc++.h>
typedef long long ll;
typedef __int128 LL;
using namespace std;

int len[4]= {1,2,3,5};
int b[66],s[6];
LL c[100][100],dp[100][100],t[4]={1,15,20,24};
int main()
{
    int n;
    LL MOD;
    ll MO;
    int TA;
    scanf("%d",&TA);
    while(TA--)
    {
        scanf("%d%lld",&n,&MO);
        MOD=MO;
        MOD*=60;
        c[0][0]=1;
        for(int i=1; i<=62; i++)
        {
            for(int j=0; j<=i; j++)
            {
                if(j==0||j==i)
                    c[i][j]=1;
                else
                    c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
            }
        }
        memset(s,0,sizeof(s));
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&b[i]);
            for(int j=0; j<4; j++)
            {
                if(b[i])
                    s[j]+=(b[i]-1)/len[j]+1;
            }
        }
        LL ans=0;
        for(int i=0; i<4; i++)
        {
            int up=60/len[i];
            if(up<s[i])continue;
            for(int j=0; j<=n; j++)
                for(int k=0; k<=up; k++)
                    dp[j][k]=0;

            dp[0][0]=1;
            for(int j=1; j<=n; j++)
            {
                int dw=b[j]?(b[j]-1)/len[i]+1:0;
                for(int k=dw; k<=up; k++)
                {
                    for(int l=dw; l<=k; l++)
                    {
                        dp[j][k]=(dp[j-1][k-l]*c[k][l]%MOD+dp[j][k])%MOD;
                    }
                }
            }
            ans=(dp[n][up]*t[i]%MOD+ans)%MOD;
        }
        ans=ans/60;
        ll an=ans;
        printf("%lld\n",an);
    }
}

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值