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;
}