luogu P4321 随机漫游 期望dp 二进制 高斯消元

Posted chdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P4321 随机漫游 期望dp 二进制 高斯消元相关的知识,希望对你有一定的参考价值。

LINK:随机漫游

非常妙的一道题。

容易想到倒推期望。

设状态 f[i][j]表示到达第i个点 此时已经到达的集合为j能走到全集的期望边数。

只要求出来这个就能O(1)回答询问。

(f[i][j]=1+sum_{vin son_x,v otin j}frac{1}{d_i}f[i][j|v]+sum_{vin son_x,vin j}frac{1}{d_i}f[i][j])

有了这个东西 显然可以((2^ncdot n)^3)暴力高斯消元了。

考虑优化 容易发现如果按照二进制的大小倒着推这个东西 那么前面那个部分完全已知了。

这样我们每次的方程最多n个 总复杂度(2^ncdot n^3)

需要卡卡常数 如 消的时候d==0可以直接break了。

const ll MAXN=19;
ll f[MAXN][1<<MAXN];//f[i][j]表示到达i这个点此时集合为j还需要跑多少才能得到全集的期望边数.
ll n,m,Q;
ll a[MAXN][MAXN],d[MAXN];
ll b[MAXN][MAXN],g[MAXN];
inline ll ksm(ll b,ll p){ll cnt=1;while(p){if(p&1)cnt=(ll)cnt*b%mod;b=(ll)b*b%mod;p=p>>1;}return cnt;}
inline void GAUSS()
{
	rep(1,n,i)
	{
		ll p=i;
		rep(i,n,j)if(b[j][i]){p=j;break;}
		if(p!=i){rep(1,n,j)swap(b[i][j],b[p][j]);swap(g[i],g[p]);}
		ll ww=ksm(b[i][i],mod-2);
		rep(1,n,j)
		{
			if(i==j)continue;
			ll d=ww*b[j][i]%mod;
			if(!d)continue;
			rep(1,n,k)b[j][k]=(b[j][k]-b[i][k]*d)%mod;
			g[j]=(g[j]-g[i]*d)%mod;
		}
	}
	rep(1,n,i)g[i]=g[i]*ksm(b[i][i],mod-2)%mod;
}
signed main()
{
	freopen("1.in","r",stdin);
	get(n);get(m);
	rep(1,m,i)
	{
		ll get(x),get(y);
		a[x][y]=a[y][x]=1;
		++d[x];++d[y];
	}
	rep(1,n,i)d[i]=ksm(d[i],mod-2);
	ll maxx=(1<<n)-1;
	fep(maxx-1,1,j)
	{
		//求出每个f[i][j].
		rep(1,n,i)
		{
			b[i][i]=1;g[i]=0;
			if(j&(1<<(i-1)))
			{
				++g[i];
				rep(1,n,k)
				{
					if(a[i][k])
					{
						if(!(j&(1<<(k-1))))g[i]=(g[i]+d[i]*f[k][j|(1<<(k-1))])%mod;
						else b[i][k]=(b[i][k]-d[i])%mod;
					}
				}
			}
		}
		GAUSS();
		rep(1,n,i)f[i][j]=(g[i]+mod)%mod;
	}
	get(Q);
	rep(1,Q,i)
	{
		ll st,s=0,get(x);
		rep(1,x,i)
		{
			ll get(y);
			s=s|(1<<(y-1));
		}
		get(st);
		putl(f[st][(maxx^s)|(1<<(st-1))]);
	}
	return 0;
}

以上是关于luogu P4321 随机漫游 期望dp 二进制 高斯消元的主要内容,如果未能解决你的问题,请参考以下文章

Luogu 1850 换教室 (期望DP)

Luogu_P4316 绿豆蛙的归宿 期望DP

luogu P1654 OSU! 概率dp

[bzoj2878][Noi2012]迷失游乐园(基环树dp)

ICPC 2005 hangzhou Generator (UVA1358)KMP + 期望DP / 高斯消元

ZROJ#398. 18提高7随机游走(期望dp 树形dp)