AtCoder-abc265_f Manhattan Cafe
Manhattan Cafe#
dp 前缀和优化
很容易想到 的状态
表示前 个点, 与 的差值和为 , 与 的差值和为
这样的话直接枚举第 组点中,我们取的点的位置,能够做到 的复杂度转移
总的时间复杂度为 ,显然超时
考虑转移的时间进行优化,我们会发现选取的位置不同,会有不同的规律,假设 ,
如果选取的点 在 ,那么 ,也就是 ,此时一定是从一个 为定值的之前的状态转移过来,这个定值就是
如果选取的点在 之外,那么与上一个转移相反,这种是从满足 为定值的状态转移过来,这个定值就是
上述转移文字可能不清楚,可以自己列表格,对每个离散点判断一下他应该从什么状态转移过来,就可以理解
因此考虑做两个对角线前缀和,每次 转移
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1e3 + 10;
typedef long long ll;
const ll mod = 998244353;
ll dp[maxn][maxn], dig[maxn][maxn], a_dig[maxn][maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, d;
cin >> n >> d;
vector<int>q(n), p(n);
for(int i=0; i<n; i++) cin >> q[i];
for(int i=0; i<n; i++) cin >> p[i];
dp[0][0] = 1;
for(int i=0; i<n; i++)
{
for(int j=0; j<=d; j++)
{
for(int k=0; k<=d; k++)
{
dig[j][k] = a_dig[j][k] = dp[j][k];
if(j && k < d)
dig[j][k] += dig[j - 1][k + 1];
if(j && k)
a_dig[j][k] += a_dig[j - 1][k - 1];
}
}
for(int j=0; j<=d; j++)
{
for(int k=0; k<=d; k++)
{
int s = abs(p[i] - q[i]);
dp[j][k] = 0;
if(k + j >= s)
{
int l = max(0, j - s), r = k + j - s - max(0, k - s);
if(l == 0) dp[j][k] += dig[r][k - s + j - r];
else dp[j][k] += dig[r][k - s + j - r] - dig[l - 1][k - s - l + j + 1];
}
if(k > s && j)
dp[j][k] += a_dig[j - 1][k - 1 - s];
if(j > s && k)
dp[j][k] += a_dig[j - 1 - s][k - 1];
dp[j][k] %= mod;
}
}
}
ll ans = 0;
for(int i=0; i<=d; i++)
for(int j=0; j<=d; j++)
ans += dp[i][j];
cout << ans % mod << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!