AtCoder-abc265_f Manhattan Cafe

Manhattan Cafe#

dp 前缀和优化

很容易想到 dp 的状态

dp[i][j][k] 表示前 i 个点,rxpx 的差值和为 jrxqx 的差值和为 k

这样的话直接枚举第 i 组点中,我们取的点的位置,能够做到 O(D) 的复杂度转移

总的时间复杂度为 O(nD3),显然超时

考虑转移的时间进行优化,我们会发现选取的位置不同,会有不同的规律,假设 pi=1qi=4

如果选取的点 ri[14],那么 |pixi|+|qixi|=|piqi|,也就是 dp[i][j][k]=dp[i1][jx][ky], x+y=|piqi|,此时一定是从一个 j+k 为定值的之前的状态转移过来,这个定值就是 j+k|piqi|

如果选取的点在 [1,4] 之外,那么与上一个转移相反,这种是从满足 jk 为定值的状态转移过来,这个定值就是 |piqi|

上述转移文字可能不清楚,可以自己列表格,对每个离散点判断一下他应该从什么状态转移过来,就可以理解

因此考虑做两个对角线前缀和,每次 O(1) 转移

#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;
}
posted @   dgsvygd  阅读(116)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
主题色彩