CodeForces-118D Caesar's Legions
Caesar's Legions
记忆化搜索
\(dp[i][j][k]\) 表示当前有 \(i\) 个步兵,\(j\) 个骑兵,同时当前的兵种(第 \(i+j\) 个)是步兵(0) 或 骑兵(1)
假设当前兵种是步兵,则可以进行记忆化搜索
\(dp[i][j][0] = \sum_{x=1}^{min(k_2, j)}(dps(i, j-x, 1))\)
同时限制骑兵的数量不大于 \(k_2\) 个
同理,如果当前兵种是骑兵,则有:
\(dp[i][j][1] = \sum_{x=1}^{min(k_1, i)}(dps(i - x, j, 0))\)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod = 1e8;
ll dp[110][110][2];
int n1, n2, k1, k2;
ll dps(int x, int y, int t)
{
if(dp[x][y][t] != -1) return dp[x][y][t];
if(x == 0 && y == 0) return dp[x][y][t] = 1;
dp[x][y][t] = 0;
ll &ans = dp[x][y][t];
if(t == 0)
{
for(int i=1; i<=min(y, k2); i++)
ans = (ans + dps(x, y-i, 1)) % mod;
}
else
{
for(int i=1; i<=min(x, k1); i++)
ans = (ans + dps(x-i, y, 0)) % mod;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n1 >> n2 >> k1 >> k2;
for(int i=0; i<=n1; i++) for(int j=0; j<=n2; j++) dp[i][j][0] = dp[i][j][1] = -1;
cout << (dps(n1, n2, 0) + dps(n1, n2, 1)) % mod << endl;
return 0;
}
如果你一直 TLE,可以继续往下看
\(dp\) 状态虽然不多,但是存在着许多无效状态,即本身 \(dp[i][j][k] = 0\),因此我们要将所有 \(dp\) 数组初始化为 \(-1\)
可以尝试一下利用下方代码输入 10 10 2 2
,就会发现大量值为 \(0\) 的状态被重复计算
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <array>
#include <map>
using namespace std;
typedef long long ll;
const ll mod = 1e8;
ll dp[110][110][2];
int n1, n2, k1, k2;
map<array<int, 3>, int>mp;
ll dps(int x, int y, int t)
{
if(dp[x][y][t]) return dp[x][y][t];
if(x == 0 && y == 0) return dp[x][y][t] = 1;
dp[x][y][t] = 0;
mp[{x, y, t}]++;
ll &ans = dp[x][y][t];
if(t == 0)
{
for(int i=1; i<=min(y, k2); i++)
ans = (ans + dps(x, y-i, 1)) % mod;
}
else
{
for(int i=1; i<=min(x, k1); i++)
ans = (ans + dps(x-i, y, 0)) % mod;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n1 >> n2 >> k1 >> k2;
cout << (dps(n1, n2, 0) + dps(n1, n2, 1)) % mod << endl;
for(auto [a, d] : mp)
{
if(d > 1)
cout << a[0] << " " << a[1] << " " << a[2] << ": " << d << endl;
}
return 0;
}