H - 扑克牌 hihocoder1159
2017-06-14 19:15
211 查看
H - 扑克牌
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 128000/64000 KB (Java/Others)Submit Status
Problem Description
一副不含王的扑克牌由52张牌组成,由红桃、黑桃、梅花、方块4组牌组成,每组13张不同的面值。现在给定52张牌中的若干张,请计算将它们排成一列,相邻的牌面值不同的方案数。牌的表示方法为XY,其中X为面值,为2、3、4、5、6、7、8、9、T、J、Q、K、A中的一个。Y为花色,为S、H、D、C中的一个。如2S、2H、TD等。
Input
第一行为一个整数T,为数据组数。之后每组数据占一行。这一行首先包含一个整数N,表示给定的牌的张数,接下来N个由空格分隔的字符串,每个字符串长度为2,表示一张牌。每组数据中的扑克牌各不相同。
1 ≤ T ≤ 2000
1 ≤ N ≤ 52
Output
对于每组数据输出一行,形如"Case #X: Y"。X为数据组数,从1开始。Y为可能的方案数,由于答案可能很大,请输出模264之后的值。Sample Input
5 1 TC 2 TC TS 5 2C AD AC JC JH 4 AC KC QC JC 6 AC AD AS JC JD KD
Sample Output
Case #1: 1 Case #2: 0 Case #3: 48 Case #4: 24 Case #5: 120
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=110; const int INF=0x3f3f3f3f; const int mod=1e9+7; int cas=1,T; LL dp[14][55],C ,fac ; int a ,n; void init() { for(int i=0;i<N;i++) { C[i][0]=C[i][i]=1; for(int j=1;j<i;j++) C[i][j]=C[i-1][j]+C[i-1][j-1]; } fac[0]=1; for(int i=1;i<N;i++) fac[i]=fac[i-1]*i; } LL Cnm(int n,int m) { if(m>n || n<0 || m<0) return 0; return C [m]; } char s [3]; int cmp(const int &a,const int &b) { return a>b; } int main() { //freopen("1.in","w",stdout); //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); init(); scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%s",s[i]); memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) { switch(s[i][0]) { case 'T':a[10]++;break; case 'J':a[11]++;break; case 'Q':a[12]++;break; case 'K':a[13]++;break; case 'A':a[1]++;break; default:a[s[i][0]-'0']++;break; } } sort(a,a+14,cmp); // for(int i=0;a[i];i++) printf("%d %d\n",i,a[i]); memset(dp,0,sizeof(dp)); dp[0][a[0]-1]=1; int sum=a[0]; LL ans=dp[0][0]; //dp第二维记录有多少个同花色相邻的 for(int i=1;a[i];i++) { for(int j=0;j<sum;j++)//多少个相邻 { for(int k=1;k<=a[i];k++)//a[i]分成多少部分 { for(int l=0;l<=k;l++)//多少部分放到相邻的中间 { LL x=j+a[i]-k-l; if(x<0) continue; dp[i][x]+=Cnm(j,l) * Cnm(sum+1-j,k-l)* Cnm(a[i]-1,k-1) * dp[i-1][j] ; } } } sum+=a[i]; ans=dp[i][0]; } for(int i=0;a[i];i++) ans=ans*fac[a[i]]; printf("Case #%d: %llu\n",cas++,ans); } //printf("time=%.3lf\n",(double)clock()/CLOCKS_PER_SEC); return 0; }
solve.cpp
题解:
本题数据加强版:http://acm.hdu.edu.cn/showproblem.php?pid=4532.
这题是一道组合数学dp.
dp数组有两维,对于dp[i][j],i表示放到第几种花色,j记录有多少个同花色相邻的出现,dp[i][j]表示方案数.
dp时,对于a[i]个同一种花色,可以将其划分为k组(将相同的a[i]个球放到k个盒子,盒子不能为空),有C(a[i]-1,k-1)种分法.
然后将k组花色按原来的顺序塞到前面已经排好的方案中,这里又有两种情况:
1.放到普通的位置
2.放到原来同花色相邻的中间,这样j就减小了
假设放l组到相邻花色中间
这里的方案数是从j个同花色相邻的位置中选l个位置出来,则有C(j,l)种方案。
假设前面有sum张牌,则有sum+1个位置,除去j个相邻位置,将剩下的k-l组放进来,有C(sum+1-j,k-l)种放法
所以最终的状态转移为
设x为放完后的同花色相邻,则x=j+a[i]-k-l;
dp[i][x]+=Cnm(j,l) * Cnm(sum+1-j,k-l)* Cnm(a[i]-1,k-1) * dp[i-1][j]
相关文章推荐
- hihocoder 1159 扑克牌(组合DP)
- hihoCoder 1159 扑克牌 编程之美2015初赛第二场
- hihoCoder 1159 扑克牌 (dp,难)
- hihocoder #1159 : 扑克牌
- hihoCoder #1159 扑克牌
- 【DP】 hihocoder #1159 : 扑克牌
- 做了个扑克牌demo(练练算法)
- 利用拿扑克牌让你几分钟搞定插入排序算法
- 制作一幅扑克牌系列二---不用图片的纯css实现方法
- 洛谷P1358 扑克牌
- 《博客园精华集 CLR分册》配套扑克牌
- hihocoder 1636 : Pangu and Stones(区间dp)
- hdu 1159 (最长公共子序列)
- HihoCoder - 1631 Cats and Fish (2017ICPC北京站 模拟)
- Poj1159——最长公共子序列
- hihocoder 1631 Cats and Fish
- 13张扑克牌排序算法
- hihoCoder挑战赛32
- 扑克牌洗牌
- java自学笔记13:简易扑克牌游戏