UOJ422 【集训队作业2018】小Z的礼物

Description

小Z有一个神奇的自动售货机,里面有$n\times m$种物品,分别放在$n$行$m$列个格子中。每当小Z向自动售货机中投入一枚硬币,他就能获得一对相邻格子中的物品(已经获得的物品可能再次获得),获得每一对相邻格子中的物品的概率是相等的。在这$n\times m$种物品中,有一些物品是小Z喜欢的(小Z喜欢的用 * [星号] 表示,其他的用 .[英文句号] 表示),他想把这些物品包装成一份礼物。小Z想知道,期望投入多少枚硬币后,就可以获得这些他喜欢的物品。

Solution

在一个$n\times m$的网格中随机选取一个$1\times 2$的区域染色,求将给定的点全部染色的期望染色次数

先Min-Max容斥一下,就变成了要求对于每个点集任意覆盖一个点的期望次数

可算出$E(T)=\frac{2mn-m-n}{x}$,$x$为点集中点的个数

但是点集的数量大的飞起,所以设$dp_{i,j,s,cnt}$为考虑到格子$(i,j)$,轮廓线左侧的$n$个格子的选取情况为$s$,$x$值为$cnt$的所有点集的容斥系数之和

每个染色区域在扫到其上方/左方格子时就记一次数,每个格子分不染色和染色两种情况讨论

挺毒的

#pragma GCC optimize(2)
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
long long n,m,dp[2][70][1205],inv[1205],sum,pre,cur=1,ans;
const long long mod=998244353;
char map[10][105];
inline long long read()
{
    long long w=0,f=1;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return w*f;
}
int main()
{
    n=read();
    m=read();
    sum=2*n*m-n-m;
    inv[0]=inv[1]=1;
    for(long long i=2;i<=sum;i++)
    {
        inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    }
    for(long long i=1;i<=n;i++)
    {
        scanf("%s",map[i]+1);
    }
    dp[cur][0][0]=mod-1;
    for(long long i=1;i<=m;i++)
    {
        for(long long j=1;j<=n;j++)
        {
            swap(cur,pre);
            memset(dp[cur],0,sizeof(dp[cur]));
            for(long long k=0;k<(1<<n);k++)
            {
                for(long long l=0;l<=sum;l++)
                {
                    long long now=k&(((1<<n)-1)^(1<<(j-1)));
                    (dp[cur][now][l]+=dp[pre][k][l])%=mod;
                    if(map[j][i]=='*')
                    {
                        now|=1<<(j-1);
                        long long cnt=0;
                        if(i>1&&!((1<<(j-1))&k))
                        {
                            ++cnt;
                        }
                        if(j>1&&!((1<<(j-2))&k))
                        {
                            ++cnt;
                        }
                        if(i<m)
                        {
                            ++cnt;
                        }
                        if(j<n)
                        {
                            ++cnt;
                        }
                        (dp[cur][now][l+cnt]+=mod-dp[pre][k][l])%=mod;
                    }
                }
            }
        }
    }
    for(long long i=0;i<(1<<n);i++)
    {
        for(long long j=1;j<=sum;j++)
        {
            (ans+=dp[cur][i][j]*inv[j])%=mod;
        }
    }
    printf("%lld\n",ans*sum%mod);
    return 0;
}
小Z的礼物

 

posted @ 2020-08-08 23:12  QDK_Storm  阅读(318)  评论(0编辑  收藏  举报