专栏文章

题解:CF118D Caesar's Legions

CF118D题解参与者 9已保存评论 15

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
15 条
当前快照
1 份
快照标识符
@miqc06gu
此快照首次捕获于
2025/12/04 02:19
3 个月前
此快照最后确认于
2025/12/04 02:19
3 个月前
查看原文

Solution:

本蒟蒻的第一篇题解,大佬轻喷(;´д`)ゞ
很显然,由数据得这种指数级别的暴搜会超时。
我们思考:上面的做法效率低下,是因为同一个状态会被访问多次。
如果我们每查询完一个状态后将该状态的信息存储下来,再次需要访问这个状态就可以直接使用之前计算得到的信息,从而避免重复计算。这充分利用了动态规划中很多问题具有大量重叠子问题的特点,属于用空间换时间的「记忆化」思想。
我们用 m[x][y][tot1][tot2] 表示在还剩 xx 个步兵和 yy 个骑兵且已有 tot1tot1tot2tot2 个骑兵或步兵连续排列情况下的方案数。

奉上AC代码:

CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e8;
int n1,n2,k1,k2,m[101][101][11][11];	//记忆化数组
int read()	//快读
{
	int x=0,a=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())
		if(c=='-') a=-1;
	for(;c>='0'&&c<='9';c=getchar())
		x=x*10+c-'0';
	return x*a;
}
int dfs(int x,int y,int tot1,int tot2)	//tot1,tot2分别表示已经选取了连续的几个步兵和骑兵,
										//x,y表示还有几个骑兵和步兵未选
{
	int ans=0;
	if(x==0&&y==0)	//方案成立,总数+1
	{
		ans=1;return ans;
	}
	if((x==0&&tot2>=k2)||(y==0&&tot1>=k1)) return 0;
	if(m[x][y][tot1][tot2]!=-1) return m[x][y][tot1][tot2];		//如果记录过直接返回
	if(x>0&&tot1<k1)
	{
		ans+=dfs(x-1,y,tot1+1,0);
		ans%=mod;
	}
	if(y>0&&tot2<k2)
	{
		ans+=dfs(x,y-1,0,tot2+1);
		ans%=mod;
	}
	m[x][y][tot1][tot2]=ans%mod;	//记录这种情况
	return ans%mod;
}
signed main()
{
//	freopen("a.in","r",stdin);
	n1=read();n2=read();
	k1=read();k2=read();
	memset(m,-1,sizeof m);	//建议赋一个比0小的初值,因为答案的情况可能为任意非负整数
	cout<<dfs(n1,n2,0,0)%mod;
	return 0;
}

评论

15 条评论,欢迎与作者交流。

正在加载评论...