[UOJ422][集训队作业2018]小Z的礼物——轮廓线DP+min-max容斥

题目链接:

[集训队作业2018]小Z的礼物

 

题目要求的就是最后一个喜欢的物品的期望得到时间。

根据$min-max$容斥可以知道$E(max(S))=\sum\limits_{T\subseteq S}^{ }(-1)^{|T|-1}E(min(T))$

那么只需要知道每个子集中最早得到的物品的期望时间即可得出答案。

对于每个子集,最早得到的物品的期望时间就是一次选择能得到这个子集中元素的概率的倒数。

用一次选择能得到这个子集中的元素的方案数除上总方案数(每次共有$2*n*m-n-m$种选择方案)就能得到对应的概率。

最暴力的方法就是枚举$2^{cnt}$个子集然后对每个求概率。

但可以发现方案数最多只有$2*n*m-n-m$个,我们可以轮廓线$DP$求出每个集合的方案数。

设$f[s][k]$表示轮廓线为$s$,方案数为$k$的集合个数。

因为容斥系数只有$-1$和$1$两种,所以在$DP$时直接将容斥系数算进去即可。

最后对于每个子集求出期望然后加和即可。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define mod 998244353
using namespace std;
int inv[1200];
int f[2][70][1200];
int n,m;
char mp[7][110];
int S,sum;
int ans;
int now,pre;
int main()
{
	scanf("%d%d",&n,&m);
	S=(1<<n)-1;
	sum=2*n*m-n-m;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",mp[i]+1);
	}
	inv[0]=inv[1]=1;
	for(int i=2;i<1200;i++)
	{
		inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	}
	f[0][0][0]=mod-1;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			pre=now,now^=1;
			memset(f[now],0,sizeof(f[now]));
			for(int s=0;s<=S;s++)
			{
				for(int k=0;k<=sum;k++)
				{
					if(f[pre][s][k])
					{
						int t=s&(S^(1<<(j-1)));
						f[now][t][k]+=f[pre][s][k],f[now][t][k]%=mod;
						if(mp[j][i]=='*')
						{
							t|=1<<(j-1);
							int num=0;
							if(j>1&&!(s&(1<<(j-2))))num++;
							if(i>1&&!(s&(1<<(j-1))))num++;
							if(i<m)num++;
							if(j<n)num++;
							f[now][t][k+num]+=mod-f[pre][s][k],f[now][t][k+num]%=mod;
						}
					}
				}
			}
		}
	}
	for(int s=0;s<=S;s++)
	{
		for(int i=1;i<=sum;i++)
		{
			ans+=1ll*f[now][s][i]*inv[i]%mod,ans%=mod;
		}
	}
	ans=1ll*ans*sum%mod;
	printf("%d",ans);
}

转载于:https://www.cnblogs.com/Khada-Jhin/p/10683651.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值