Luogu P5279 [ZJOI2019]麻将

ZJOI2019神题，间接送我退役的神题233

2.期望DP

$ans=\sum_{i=1}^m \frac{f_i\cdot i!\cdot(m-i)!}{m!}+1$

CODE

#include<cstdio>
#include<cstring>
#include<map>
#define RI register int
#define CI const int&
using namespace std;
const int N=105,MX=2100,mod=998244353;
inline void maxer(int& x,CI y)
{
if (y>x) x=y;
}
inline int min(CI a,CI b)
{
return a<b?a:b;
}
struct Matrix
{
int mat[3][3];
inline int* operator [] (CI x) { return mat[x]; }
inline Matrix(void)
{
memset(mat,-1,sizeof(mat));
}
friend inline bool operator != (Matrix A,Matrix B)
{
for (RI i=0;i<3;++i) for (RI j=0;j<3;++j)
if (A[i][j]!=B[i][j]) return 1; return 0;
}
friend inline bool operator < (Matrix A,Matrix B)
{
for (RI i=0;i<3;++i) for (RI j=0;j<3;++j)
if (A[i][j]!=B[i][j]) return A[i][j]<B[i][j];
}
inline bool Com_Hu(void)
{
for (RI i=0;i<3;++i) for (RI j=0;j<3;++j)
if (mat[i][j]>=4) return 1; return 0;
}
inline void flush(Matrix pre,CI num)
{
for (RI i=0;i<3;++i) for (RI j=0;j<3;++j)
if (~pre[i][j]) for (RI k=0;k<3&&i+j+k<=num;++k)
maxer(mat[j][k],min(i+pre[i][j]+(num-i-j-k)/3,4));
}
};
struct Hu_Auto_Node
{
Matrix p[2]; int cur,ch[5];
inline Hu_Auto_Node(void)
{
memset(ch,0,sizeof(ch)); cur=0; p[0]=p[1]=Matrix();
}
inline bool is_Hu(void)
{
if (cur>=7) return 1; return p[1].Com_Hu();
}
inline void Hu(void)
{
memset(ch,0,sizeof(ch)); cur=-1; p[0]=p[1]=Matrix();
}
friend inline bool operator < (Hu_Auto_Node A,Hu_Auto_Node B)
{
if (A.cur!=B.cur) return A.cur<B.cur;
if (A.p[0]!=B.p[0]) return A.p[0]<B.p[0];
if (A.p[1]!=B.p[1]) return A.p[1]<B.p[1]; return 0;
}
friend inline Hu_Auto_Node operator + (Hu_Auto_Node A,CI num)
{
if (A.is_Hu()) return A.Hu(),A; Hu_Auto_Node s;
s.p[0].flush(A.p[0],num); s.p[1].flush(A.p[1],num);
if (num>=2) s.p[1].flush(A.p[0],num-2);
s.cur=A.cur+(num>=2); if (s.is_Hu()) s.Hu(); return s;
}
};
class Hu_Automation
{
private:
map <Hu_Auto_Node,int> Hash;
inline void expand(CI id)
{
for (RI i=0;i<=4;++i)
{
Hu_Auto_Node son=node[id]+i;
if (!Hash.count(son)) node[Hash[son]=++tot]=son;
node[id].ch[i]=Hash[son];
}
}
public:
Hu_Auto_Node node[2100]; int tot;
inline Hu_Automation(void)
{
node[1].p[0][0][0]=0; node[tot=2].cur=-1;
Hash[node[1]]=1; Hash[node[2]]=2; expand(1);
for (RI i=3;i<=tot;++i) expand(i);
}
/*inline void check(void)
{
printf("%d\n",tot); for (RI i=1;i<=tot;++i,putchar('\n'))
for (RI j=0;j<=4;++j) printf("%d ",node[i].ch[j]);
}*/
}HA;
int f[2][N<<2][MX],a[N],fact[N<<2],inv[N<<2],n,m,x,y,nw,ans;
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
for (inv[n]=quick_pow(fact[n]),i=n-1;~i;--i) inv[i]=1LL*inv[i+1]*(i+1)%mod;
}
inline int C(CI n,CI m)
{
return 1LL*fact[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void calc(CI x,CI y)
{
inc(ans,1LL*f[nw][x][y]*fact[x]%mod*fact[m-x]%mod);
}
int main()
{
RI i,j,k,t; for (scanf("%d",&n),i=1;i<=13;++i) scanf("%d%d",&x,&y),++a[x];
for (init(m=(n<<2)-13),f[0][0][1]=i=1;i<=n;++i)
for (nw=i&1,memset(f[nw],0,sizeof(f[nw])),j=m;~j;--j)
for (k=1;k<=HA.tot;++k) if (f[nw^1][j][k]) for (t=0;t<=4-a[i];++t)
inc(f[nw][j+t][HA.node[k].ch[a[i]+t]],1LL*f[nw^1][j][k]*C(4-a[i],t)%mod);
for (nw=n&1,i=1;i<=m;++i) for (calc(i,1),j=3;j<=HA.tot;++j) calc(i,j);
return printf("%d",(1LL*ans*inv[m]%mod+1)%mod),0;
}
posted @ 2019-04-18 21:19 hl666 阅读(...) 评论(...) 编辑 收藏