Luogu5370 [PKUSC2018]主斗地

https://www.luogu.com.cn/problem/P5370

模拟/贪心

答案是百万级别的,对\(998244353\)取模是吓人的

对子、三张牌、顺子、连对、三顺一点用都没有,因为它们当成单牌打不会更劣

飞机都没用,它们都可以由三带一、三带二代替

所以有用的只有:

单牌、三带一、三带二、四带二

单牌可以最后一次性处理完毕,三带一、三带二、四带二暴力枚举

剪枝见代码

\(Code:\)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("-O2")
#pragma GCC optimize("-O3")
#include<iostream>
#include<cstdio>
#include<algorithm>
#define rint register int
#define min(x,y) ((x<y)?x:y)
#define max(x,y) ((x>y)?x:y)
using namespace std;
int ans,cc,turn[305],kl[15],rkl[15],xx[15],rxx[15],p[15];
char S[20];
bool flag=true;
void ins(char c)
{
    turn[c]=++cc;
    p[cc]=(c!='w' && c!='W')?4:1;
}
bool Check(rint q,rint d)//判断当前情况是否可行(枚举对子数)
{
    //除去对子(三带二)
    //贪心,九条可怜带大牌,xx网友带小牌
    int gc=0,r;
    for (rint i=cc-2;i>=1 && gc<q;i--)
    {
        r=min(q-gc,kl[i] >> 1);
        gc+=r,kl[i]-=r << 1;
    }
    if (gc!=q)
    {
        flag=false;
        return false;
    }
    gc=0;
    for (rint i=1;i<=cc-2 && gc<q;i++)
    {
        r=min(q-gc,xx[i] >> 1);
        gc+=r,xx[i]-=r << 1;
    }
    if (gc!=q)
    {
        flag=false;
        return false;
    }
    //三带一、四带二
    gc=0;
    for (rint i=cc;i>=1 && gc<d;i--)
    {
        r=min(d-gc,kl[i]);
        gc+=r,kl[i]-=r;
    }
    if (gc!=d)
        return false;
    gc=0;
    for (rint i=1;i<=cc && gc<d;i++)
    {
        r=min(d-gc,xx[i]);
        gc+=r,xx[i]-=r;
    }
    if (gc!=d)
        return false;
    //单牌
    if (kl[cc])
        return false;
    int u=xx[cc];
    for (rint i=cc-1;i>=1;i--)
    {
        if (u<kl[i])
            return false;
        u=u-kl[i]+xx[i];
    }
    return true;
}
bool Pair(rint three,rint four)//枚举对子数(用于三带二)
{
    int klt=0,xxt=0;
    for (rint i=1;i<=cc-2;i++)
    {
        klt+=kl[i] >> 1;
        xxt+=xx[i] >> 1;
    }
    xxt=min(three,min(xxt,klt));
    for (rint i=1;i<=cc;i++)
        rkl[i]=kl[i],rxx[i]=xx[i];
    for (rint i=0;i<=three;i++)
        if (Check(i,three+four*2-i))
        {
            for (rint j=1;j<=cc;j++)
                kl[j]=rkl[j],xx[j]=rxx[j];
            return true;
        } else
        {
            for (rint j=1;j<=cc;j++)
                kl[j]=rkl[j],xx[j]=rxx[j];
            if (!flag)
            {
                flag=true;
                return false;
            }
        }
    return false;
}
//now表示取到哪种牌
//kt表示九条可怜的三张牌对数
//kf表示九条可怜的四张牌对数
//xt表示xx网友的三张牌对数
//xf表示xx网友的四张牌对数
bool Dfs(int now,int kt,int kf,int xt,int xf)
{
    //如果牌数超过17,直接返回
    if (max(kt,xt)*4+max(kf,xf)*6>17)
        return false;
    //九条可怜的三张牌或四张牌比xx网友大
    if (kt<xt || kf<xf)
        return false;
    //牌没了
    if (now>turn['2'])
    {
        if (kt!=xt || kf!=xf)
            return false;
        return Pair(kt,kf);
    }
    //九条可怜-四张牌
    if (kl[now]>=4)
    {
        kl[now]-=4;
        bool t=Dfs(now+1,kt,kf+1,xt,xf);
        kl[now]+=4;
        if (t)
            return true;
    }
    //九条可怜-三张牌
    if (kl[now]>=3)
    {
        kl[now]-=3;
        bool t=Dfs(now+1,kt+1,kf,xt,xf);
        kl[now]+=3;
        if (t)
            return true;
    }
    //xx网友-四张牌
    if (xx[now]>=4)
    {
        xx[now]-=4;
        bool t=Dfs(now+1,kt,kf,xt,xf+1);
        xx[now]+=4;
        if (t)
            return true;
    }
    //xx网友-三张牌
    if (xx[now]>=3)
    {
        xx[now]-=3;
        bool t=Dfs(now+1,kt,kf,xt+1,xf);
        xx[now]+=3;
        if (t)
            return true;
    }
    return Dfs(now+1,kt,kf,xt,xf);
}
//T表示枚举到哪一种牌
//now表示现在还需取几张牌
void Shuffle_The_Cards(int T,int now)//洗牌
{
    if (!now)
    {
        ans+=Dfs(1,0,0,0,0);
        return;
    }
    if (T>turn['W'])
        return;
    for (int i=xx[T];i<=p[T];i++)
    {
        if (i-xx[T]>now)
            break;
        kl[T]=i-xx[T];
        Shuffle_The_Cards(T+1,now-kl[T]);
        kl[T]=0;
    }
}
int main()
{
    for (char i='4';i<='9';i++)
        ins(i);
    ins('T'),ins('J'),ins('Q'),ins('K'),ins('A'),ins('2'),ins('w'),ins('W');
    while (~scanf("%s",S+1))
    {
        ans=0;
        for (int i=1;i<=cc;i++)
            xx[i]=0;
        for (int i=1;i<=17;i++)
            xx[turn[S[i]]]++;
        Shuffle_The_Cards(1,17);
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2020-08-05 20:18  GK0328  阅读(173)  评论(0编辑  收藏  举报