2021.08.18 CF1519B The Cake Is a Lie

CF1519B   The   Cake   Is   a   Lie \color{green}{\texttt{CF1519B The Cake Is a Lie}} CF1519B The Cake Is a Lie

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

在这里插入图片描述

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

看到题目,应该可以想到一个比较经典的递推套路:记 f i , j , k f_{i,j,k} fi,j,k 表示从 ( 1 , 1 ) (1,1) (1,1) 走到 ( i , j ) (i,j) (i,j),是否可以刚好获得 k k k 点分数。

显然,如果 f i , j , k f_{i,j,k} fi,j,k 的值为真(即可以刚好获得 k k k 点分数),则 f i , j + 1 , k + i f_{i,j+1,k+i} fi,j+1,k+i f i + 1 , j , k + j f_{i+1,j,k+j} fi+1,j,k+j 都应该是真(分别题目中的转移 1 , 2 1,2 1,2)。

但是,每次求 f n , m , k f_{n,m,k} fn,m,k 的时间复杂度是 O ( n × m × k ) \mathcal{O}(n \times m \times k) O(n×m×k) 的,再乘上数据组数 T T T,很有机会会 TLE。

不过,由于对于确定的 n , m , k n,m,k n,m,k 而言, f n , m , k f_{n,m,k} fn,m,k 的值是确定的,所以我们可以提前计算出所有的 f n , m , k f_{n,m,k} fn,m,k,然后就可以 O ( 1 ) \mathcal{O}(1) O(1) 回答每个询问了。

最后的总时间复杂度为 O ( max ⁡ { n m k } + T ) \mathcal{O}(\max \{nmk \}+T) O(max{nmk}+T)

[Code] \color{blue}{\texttt{[Code]}} [Code]

int T,n,m,k,Q;
bool f[110][110][10100];
int main(){
	memset(f,false,sizeof(f));
	f[1][1][0]=true;//初始化 
	for(int i=1;i<=100;i++)
		for(int j=1;j<=100;j++)
			for(int k=0;k<=10000;k++)
				if (f[i][j][k]){
					if (k+i<=10000) f[i][j+1][k+i]=true;
					if (k+j<=10000) f[i+1][j][k+j]=true;
				}
	scanf("%d",&Q);
	for(T=1;T<=Q;T++){
		scanf("%d%d%d",&n,&m,&k);
		if (f[n][m][k]) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

[Afterword] \color{blue}{\texttt{[Afterword]}} [Afterword]

其实这个递推的方法对于这一类题目是很有效的。

但是,本题也有另一种思考方法,即用一个递归函数 f ( n , m , k ) f(n,m,k) f(n,m,k) 判断从 ( 1 , 1 ) (1,1) (1,1) 走到 ( n , m ) (n,m) (n,m) 可否刚好获得 k k k 点分数。

要计算 f ( n , m , k ) f(n,m,k) f(n,m,k),你显然会去求 f ( n , m − 1 , k − n ) f(n,m-1,k-n) f(n,m1,kn) f ( n − 1 , m , k − m ) f(n-1,m,k-m) f(n1,m,km) 的值。然后你会发现,这个递归函数是可以记忆化的,也可以在 O ( max ⁡ { n m k } ) \mathcal{O}(\max \{ nmk \}) O(max{nmk}) 的时间内求出所有的答案。而且不需要预处理,记忆化可以保证不会炸。

再把递归改为递推就可以得到本题的填表法型转移方程式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值