zoukankan      html  css  js  c++  java
  • Solution -「洛谷 P4007」小 Y 和*的奴隶主

    Description

    Link.

    这道题 的加强版。

    Solution

    题解里面大多数都是概率 DP,或者是期望 DP 然后是逆推。甚至不给 DP 的转移式。机房 yyds Reanap 发了一篇逆推的题解,那我就来补一篇正推的期望 DP 的填表法做法。

    首先这道题看上去好像可以状压的样子,我们可以设 (f_{i,S}) 表示当前打了 (i) 次,敌方的情况是 (S) 的期望。

    不过仔细想一下发现我们只需要知道各种血量的奴隶主有多少即可。

    于是我们重新设计 DP 的状态:(f_{s,i,j,k}) 表示目前打了 (s) 次,敌方分别有 (i)(j)(k) 个 1hp、2hp、3hp 的奴隶主。

    首先我们令 (T=[i+j+k<K])

    那么我们的方程就是:

    [f_{s,i,j,k}=egin{cases} f_{s-1,i-1,j,k}+frac{i}{i+j+k+1},M=1land i eq0 \ f_{s-1,i-1,j,k}+frac{i}{i+j+k+1},M=2land i eq0 \ f_{s-1,i+1,j-1+T,k}+frac{j}{i+j+k+1},M=2land j eq0 \ f_{s-1,i-1,j,k}+frac{i}{i+j+k+1},M=3land i eq0 \ f_{s-1,i+1,j-1,k+T}+frac{j}{i+j+k+1},M=3land j eq0 \ f_{s-1,i,j+1,k-1+T}+frac{k}{i+j+k+1},M=3land k eq0 end{cases} ]

    这个方程挺好理解的,基本就等于照题意模拟。

    然后我们发现转移式中的系数部分和 (f) 数组没有关系,所以我们可以用矩阵来加速这个东西。

    数一数状态数,直接加速直接 T 飞。

    有一个矩阵加速常用的 trick,预处理矩阵 2 的幂。

    然后取模卡卡常即可。

    (代码不保证稳定能过)

    #include <cstdio>
    #define mod ( 998244353 )
    
    using namespace std;
    typedef long long LL;
    
    char buf[1 << 21], *p1 = buf, *p2 = buf;
    #define getchar( ) ( p1 == p2 && ( p2 = ( p1 = buf ) + fread( buf, 1, 1 << 21, stdin ), p1 == p2 ) ? EOF : *p1 ++ )
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;
    	char c = getchar( );
    	_T f = 1;
    	while( c < '0' || c > '9' )
    	{
    		if( c == '-' )	f = -1;
    		c = getchar( );
    	}
    	while( c >= '0' && c <= '9' )	x = ( x << 3 ) + ( x << 1 ) + ( c ^ '0' ), c = getchar( );
    	x *= f;
    }
    
    template<typename _T, typename... Args>
    void read( _T &t, Args&... args ) { read( t ), read( args... ); }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 )	putchar( '-' ), x = -x;
    	if( x > 9 )	write( x / 10 );
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    void Add( _T &x, _T y )
    {
    	if( y >= mod )  y %= mod;
    	x += y;
    	if( x >= mod )  x -= mod;
    }
    
    template<typename _T>
    _T square( _T x ) { return x * x; }
    
    const int Maxn = 10 + 5, Maxk = 170 + 5;
    int T, M, K, S, Unite[Maxn][Maxn][Maxn];
    LL tmp[Maxk], Ans[Maxk], Inv[Maxn];
    struct Matrix
    {
    	LL mat[Maxk][Maxk];
    
    	friend Matrix operator * ( const Matrix &one, const Matrix &another )
    	{
    		Matrix res;
    		for( int i = 0; i <= S + 1; ++ i )
    		{
    			for( int j = 0; j <= S + 1; ++ j )
    			{
    				res.mat[i][j] = 0;
    				for( int k = 0; k <= S + 1; ++ k )	Add( res.mat[i][j], one.mat[i][k] * another.mat[k][j] );
    			}
    		}
    		return res;
    	}
    } dp[Maxk];
    
    template<typename _T>
    _T qkpow( _T base, _T times )
    {
    	_T res = 1;
    	while( times )
    	{
    		if( times & 1 )	res = ( LL )res * base % mod;
    		base = ( LL )base * base % mod;
    		times >>= 1;
    	}
    	return res;
    }
    
    void progressInversions( ) { for( int i = 0; i <= 10; ++ i )	Inv[i] = qkpow( i, mod - 2 ); }
    signed main( )
    {
    	progressInversions( );
    	read( T, M, K );
    	for( int i = 0; i <= K; ++ i )
    	{
    		int UpI;
    		if( M > 1 )	UpI = K - i;
    		else	UpI = 0;
    		for( int j = 0; j <= UpI; ++ j )
    		{
    			int UpJ;
    			if( M > 2 )	UpJ = K - i - j;
    			else	UpJ = 0;
    			for( int k = 0; k <= UpJ; ++ k )	Unite[i][j][k] = ++ S;
    		}
    	}
    	for( int i = 0; i <= K; ++ i )
    	{
    		int UpI;
    		if( M > 1 )	UpI = K - i;
    		else	UpI = 0;
    		for( int j = 0; j <= UpI; ++ j )
    		{
    			int UpJ;
    			if( M > 2 )	UpJ = K - i - j;
    			else	UpJ = 0;
    			for( int k = 0; k <= UpJ; ++ k )
    			{
    				int Add;
    				if( i + j + k < K )	Add = 1;
    				else	Add = 0;
    				if( M == 1 && i )	dp[0].mat[Unite[i][j][k]][Unite[i - 1][j][k]] = ( LL )i * Inv[i + j + k + 1] % mod;
    				else if( M == 2 )
    				{
    					if( i )	dp[0].mat[Unite[i][j][k]][Unite[i - 1][j][k]] = ( LL )i * Inv[i + j + k + 1] % mod;
    					if( j )	dp[0].mat[Unite[i][j][k]][Unite[i + 1][j - 1 + Add][k]] = ( LL )j * Inv[i + j + k + 1] % mod;
    				}
    				else if( M == 3 )
    				{
    					if( i )	dp[0].mat[Unite[i][j][k]][Unite[i - 1][j][k]] = ( LL )i * Inv[i + j + k + 1] % mod;
    					if( j )	dp[0].mat[Unite[i][j][k]][Unite[i + 1][j - 1][k + Add]] = ( LL )j * Inv[i + j + k + 1] % mod;
    					if( k )	dp[0].mat[Unite[i][j][k]][Unite[i][j + 1][k - 1 + Add]] = ( LL )k * Inv[i + j + k + 1] % mod;
    				}
    				dp[0].mat[Unite[i][j][k]][Unite[i][j][k]] = dp[0].mat[Unite[i][j][k]][S + 1] = Inv[i + j + k + 1];
    			}
    		}
    	}
    	dp[0].mat[S + 1][S + 1] = 1;
    	for( int i = 1; i <= 60; ++ i )	dp[i] = square( dp[i - 1] );
    	while( T -- > 0 )
    	{
    		LL N;
    		read( N );
    		for( int i = 0; i <= S + 1; ++ i )  Ans[i] = 0;
    		if( M == 1 )	Ans[Unite[1][0][0]] = 1;
    		else if( M == 2 )	Ans[Unite[0][1][0]] = 1;
    		else	Ans[Unite[0][0][1]] = 1;
    		for( int i = 0; i <= 60; ++ i )
    		{
    			if( ( N >> i ) & 1 )
    			{
    				for( int j = 0; j <= S + 1; ++ j )
    				{
    					tmp[j] = 0;
    					for( int k = 0; k <= S + 1; ++ k )	Add( tmp[j], Ans[k] * dp[i].mat[k][j] );
    				}
    				for( int j = 0; j <= S + 1; ++ j )	Ans[j] = tmp[j];
    			}
    		}
    		write( Ans[S + 1] ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    Atitit attilax要工作研究的要素 纪要 方案 趋势 方向 概念 理论
    Atitit 常见每日流程日程日常工作.docx v7 r8f
    Atitit it 互联网 软件牛人的博客列表
    Atitit 信息链(Information Chain)的概念理解 attilax总结
    Atitit 知识点的体系化 框架与方法 如何了解 看待xxx
    Atitit 聚合搜索多个微博 attilax总结
    Atitit 企业知识管理PKM与PIM
    Atitit 项目沟通管理 Atitit 沟通之道 attilax著.docx
    Atitit 项目管理软件 在线服务 attilax总结 1. 项目管理协作的历史 1 1.1. Worktile 406k 1 1.2. Teambition  584k in baidu
    Atitit.每周末总结 于每周一计划日程表 流程表 v8 import 上周遗漏日志补充 检查话费 检查流量情况 Crm问候 Crm表total and 问候
  • 原文地址:https://www.cnblogs.com/orchid-any/p/13750811.html
Copyright © 2011-2022 走看看