zoukankan      html  css  js  c++  java
  • 题解 CH5E26 【扑克牌】

    题目链接:Link

    Problem

    Solution

    首先不难想到,至少要记录四个状态:“有4种颜色的牌的面值个数”“有3种颜色的牌的面值个数”……
    然后尝试再记录一个状态:当前状态动的那个牌的面值的颜色数。但这样会导致边界条件特判过于麻烦。
    考虑进行如下容斥:
    当动有1种颜色的牌时,显然 $ add = c1 * f(c4,c3,c2,c1-1) $ 。
    当动有2种颜色的牌时,显然 $ add += 2 * c2 * dp(c4,c3,c2-1,c1+1) $ ,但我们要考虑减去连出2次相同面值的牌的行为,即 $ add -= 2 * c2 * dp(c4,c3,c2-1,c1) $
    当动有3种颜色的牌时,显然要加上至少连出1次同样面值的牌的行为,但由于后面2~3位已保证不会重复,多减去了,所以还要加回来。通4种颜色的情况一样,容斥即可。

    Code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef unsigned long long ULL;
    int T,kase,n,h1[128],cnt1[14],cnt2[5];
    ULL f[14][14][14][14];
    ULL dp(int c4,int c3,int c2,int c1)
    {
    	ULL &res=f[c4][c3][c2][c1];
    	if(res!=-1ull) return res;
    	res=0;
    	if(c1>0) res+=1ull*c1*dp(c4,c3,c2,c1-1);
    	if(c2>0) res+=2ull*c2*(dp(c4,c3,c2-1,c1+1)-dp(c4,c3,c2-1,c1));
    	if(c3>0) res+=3ull*c3*(dp(c4,c3-1,c2+1,c1)-2ull*(dp(c4,c3-1,c2,c1+1)-dp(c4,c3-1,c2,c1)));
    	if(c4>0) res+=4ull*c4*(dp(c4-1,c3+1,c2,c1)-3ull*(dp(c4-1,c3,c2+1,c1)-2ull*(dp(c4-1,c3,c2,c1+1)-dp(c4-1,c3,c2,c1))));
    	return res;
    }
    int main()
    {
    	#ifdef local
    	freopen("pro.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	h1['A']=1;
    	for(int i='2';i<='9';i++) h1[i]=i-'0';
    	h1['T']=10; h1['J']=11; h1['Q']=12; h1['K']=13;
    	memset(f,-1,sizeof(f));
    	f[0][0][0][0]=1;
    	while(T-->0)
    	{
    		scanf("%d",&n);
    		char s[3];
    		FU(i,1,13) cnt1[i]=0;
    		for(int i=0;i<n;i++)
    		{
    			scanf("%s",s);
    			cnt1[h1[s[0]]]++;
    		}
    		FU(i,1,4) cnt2[i]=0;
    		FU(i,1,13) cnt2[cnt1[i]]++;
    		printf("Case #%d: %llu
    ",++kase,dp(cnt2[4],cnt2[3],cnt2[2],cnt2[1]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    拓展欧几里得
    使用BIOS进行键盘输入和磁盘读写
    直接定址表
    指令系统总结
    端口
    内中断
    标志寄存器
    call 和 ret 指令
    编写包含多个功能子程序的中断例程
    字符串的输入
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11638123.html
Copyright © 2011-2022 走看看