[unknown OJ] 游戏

该博客介绍了如何解决一道动态规划题目,当x+y+z不是3的倍数时,问题无解。博主首先暴力求解,然后通过差分形式定义状态dp[i][j],并详细阐述了状态转移方程。在处理特殊情况时,博主发现转移存在环,通过手动消元避免了高斯消元,最终得出O(n^2)的时间复杂度解法,得到70分。为了获得剩余30分,博主提出考虑马走日问题的组合数计算,直接计算dp值的贡献。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目

点此看题

二、解法

x + y + z x+y+z x+y+z 不是 3 3 3的倍数的时候无解。

一看就是 d p dp dp 的题了,先把暴力一下的写出来,设 d p [ i ] [ j ] dp[i][j] dp[i][j] 为这个状态到分配完成的期望轮数( i = z − x , j = z − y i=z-x,j=z-y i=zx,j=zy z z z最大),也就是我们用一个差分的形式来表示状态,转移:
d p [ a ] [ b ] = 1 2 d p [ a − 2 ] [ b − 1 ] + 1 2 d p [ a − 2 ] [ b − 1 ] + 1 dp[a][b]=\frac{1}{2}dp[a-2][b-1]+\frac{1}{2}dp[a-2][b-1]+1 dp[a][b]=21dp[a2][b1]+21dp[a2][b1]+1但是还没完,当 b = 1 b=1 b=1 时转移是这样的:
d p [ a ] [ 1 ] = d p [ a − 2 ] [ 0 ] + 2 dp[a][1]=dp[a-2][0]+2 dp[a][1]=dp[a2][0]+2这种转移是可以根据样例发现的,通过 2 2 2轮的期望就可以完成把最高的填到最矮的操作。当出现等高的情况转移也比较特殊,也就是 b = 0 b=0 b=0 的情况是这样子的:
d p [ a ] [ 0 ] = 1 2 d p [ a + 1 ] [ 2 ] + 1 2 d p [ a − 1 ] [ 1 ] + 1 dp[a][0]=\frac{1}{2}dp[a+1][2]+\frac{1}{2}dp[a-1][1]+1 dp[a][0]=21dp[a+1][2]+21dp[a1][1]+1发现转移有环,但肯定不能高斯消元来解决,但转移的环仅限于 b = 0 / 1 b=0/1 b=0/1 的情况,我们看能不能用手动消元的方式消掉,因为 d p [ a ] [ 0 ] dp[a][0] dp[a][0] 的方程中有 d p [ a + 1 ] [ 2 ] dp[a+1][2] dp[a+1][2],那我们就从他入手消元:
2 d p [ a ] [ 0 ] = d p [ a − 1 ] [ 1 ] + d p [ a ] [ 0 ] + 1 2 + d p [ a − 1 ] [ 1 ] + 1 2dp[a][0]=\frac{dp[a-1][1]+dp[a][0]+1}{2}+dp[a-1][1]+1 2dp[a][0]=2dp[a1][1]+dp[a][0]+1+dp[a1][1]+1 d p [ a ] [ 0 ] = d p [ a − 1 ] [ 1 ] + 2 dp[a][0]=dp[a-1][1]+2 dp[a][0]=dp[a1][1]+2 d p [ a ] [ 0 ] = d p [ a − 3 ] [ 0 ] + 4 dp[a][0]=dp[a-3][0]+4 dp[a][0]=dp[a3][0]+4推到这里不难看出:
d p [ a ] [ 0 ] = 4 3 a     d p [ a ] [ 1 ] = 4 a − 2 3 dp[a][0]=\frac{4}{3}a\space\space\space dp[a][1]=\frac{4a-2}{3} dp[a][0]=34a   dp[a][1]=34a2那么转移到这里就不存在环了,我们可以愉快的 O ( n 2 ) O(n^2) O(n2) 转移拿到 70 70 70 分。

最后 30 30 30 分需要观察 d p [ a ] [ b ] dp[a][b] dp[a][b] 转移的性质,发现他的过程就是 马走日 ,而我们知道马走日问题是可以用组合数计算的,那么这道题能不能引入组合数直接算答案呢?

明确思路,我们不转移了,直接算 d p [ a ] [ 0 ] dp[a][0] dp[a][0] d p [ a ] [ 1 ] dp[a][1] dp[a][1] 对答案 d p [ x ] [ y ] dp[x][y] dp[x][y] 的贡献,可以看下图:
在这里插入图片描述

我们就是要算系数,那么系数是 2 − k 2^{-k} 2k 次方,对于底层点(也就是我们处理出来的 b = 0 / 1 b=0/1 b=0/1的点)的 d p dp dp 值贡献和常数贡献都可以用这个系数呈上方案数计算(常数贡献是 k × 2 − k k\times 2^{-k} k×2k

时间复杂度 O ( n ) O(n) O(n)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 1000005;
const int MOD = 998244353;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,x,y,ans,a[5],fac[M],inv[M],bin[M],f0[M],f1[M];
void init(int n)
{
	fac[0]=inv[0]=inv[1]=bin[0]=1;
	for(int i=2;i<=n;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=1;i<=n;i++) fac[i]=i*fac[i-1]%MOD;
	for(int i=2;i<=n;i++) inv[i]=inv[i-1]*inv[i]%MOD;
	for(int i=1;i<=n;i++) f0[i]=4*i/3;
	for(int i=1;i<=n;i++) f1[i]=(4*i-2)/3;
	for(int i=1;i<=n;i++) bin[i]=bin[i-1]*inv[2]%MOD;
}
int C(int n,int m)
{
	if(n<m || n<0 || m<0) return 0;
	return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
signed main()
{
	init(1e6);
	T=read();
	while(T--)
	{
		a[0]=read();a[1]=read();a[2]=read();
		sort(a,a+3);ans=0;
		int p=a[2]-a[0],q=a[2]-a[1];
		if((p+q)%3)
		{
			puts("-1");
			continue;
		}
		for(int i=1;i<=max(p,q);i++)
		{
			if(i%3) continue;
			//这是(i,0)的贡献 
			int x=p-i,y=q,st=(x+y)/3,tmp=0;
			if(st>=0)
			{
				tmp=C(st,x-st)-C(st-1,x-st-1);//减去(i+2,1)的贡献
				ans=(ans+(f0[i]+st)*tmp%MOD*bin[st])%MOD;
			}
			//这是(0,i)的贡献
			x=p;y=q-i;st=(x+y)/3;
			if(st>=0)
			{
				tmp=C(st,y-st)-C(st-1,y-st-1);//减去(1,i+1)的贡献
				ans=(ans+(f0[i]+st)*tmp%MOD*bin[st])%MOD;
			}
		}
		for(int i=1;i<=max(p,q);i++)
		{
			if(i%3!=2) continue;
			//这是(i,1)的贡献 
			int x=p-i,y=q-1,st=(x+y)/3,tmp=0;
			if(st>=0)
			{
				tmp=C(st,x-st);
				ans=(ans+(f1[i]+st)*tmp%MOD*bin[st])%MOD;
			}
			//这是(1,i)的贡献
			x=p-1;y=q-i;st=(x+y)/3;
			if(st>=0)
			{
				tmp=C(st,y-st);
				ans=(ans+(f1[i]+st)*tmp%MOD*bin[st])%MOD;
			}
		}
		printf("%lld\n",(ans+MOD)%MOD); 
	}
}
### 关于东华大学OJ平台上棋盘游戏题目的解题思路 对于东华大学在线评测系统(OJ)中的棋盘游戏题目,特别是涉及复杂逻辑推理和算法设计的问题,建议采取逐步深入的方法来理解和解决问题。 #### 对于遇到难题时的态度 面对完全无从下手的情况,保持耐心非常重要。不应立即寻求他人帮助或查看解答,而是尝试转换思维角度,通过解决其他类型的题目积累经验后再回头审视原问题[^1]。这种策略有助于培养独立思考能力和提高编程技巧。 #### 以2n皇后问题为例的具体分析 具体到像“2n皇后问题”这样的经典棋盘布局挑战,在实现过程中需要注意几个方面: - **初始化阶段**:仔细解析给定的输入数据——即棋盘状态矩阵,其中`0`表示该位置不可放置皇后。 - **核心算法设计**:采用深度优先搜索(DFS)作为主要手段来进行穷举可能的状态空间树。每次递归调用都需要确保新加入的一对黑白皇后满足以下条件: - 不在同一行; - 不在同一列; - 斜向也不冲突; - 黑白两个皇后不在同一个单元格内。 这里给出一段简化版Python代码框架用于演示如何构建上述过程: ```python def dfs(board, row): global count if row >= n: count += 1 return for col_black in range(n): if not is_safe(board, row, col_black,'black'): continue board[row][col_black]='B' for col_white in range(n): if (not is_safe(board, row, col_white,'white') or col_white==col_black):continue board[row][col_white]='W' dfs(board,row+1) board[row][col_white]=0 board[row][col_black]=0 def is_safe(board,x,y,color): # Check this row on left side and diagonal positions... pass count=0 board=[[0]*8 for _ in range(8)] dfs(board,0) print(count) ``` 此段伪代码展示了基本框架,实际应用中还需要完善`is_safe()`函数以及其他边界情况处理机制。 #### 总结 综上所述,针对此类棋盘类竞赛题目,除了掌握必要的回溯法等基础知识外,更重要的是锻炼自己的抽象建模能力以及灵活运用已有知识的能力。同时也要注意避免常见的错误陷阱,比如忽视某些特殊情况下的约束条件验证等问题[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值