ABC265 E - Warp

DP

https://atcoder.jp/contests/abc265/tasks/abc265_e

题意

有个人初始在原点,有三个向量 \(v[0],v[1],v[2]\), 每次操作可以选择任意一个向量,若当前在 \(p\) 点,可以瞬移\(p+v\),一共有 n 次操作(n<=300)

有 m 个陷阱(m<=1e5),陷阱的地方不能到达,求这个人完成这 n 次操作的路径的方案数

思路

由于 n 很小,可以设 \(f[w][i][j]\) 表示已经走了 w 次,k = w - i - j, \((i,j,k)\) 表示三个向量分别走了 i, j, k 次

\(f[w][i][j]\) 为路径的方案数

陷阱用 set 存起来判断即可,注意到是瞬移,所以只需要在某次操作的终点判断是不是在陷阱上,不需要在这次操作对应的线段上判断

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
#define endl "\n"

typedef long long ll;
const int N = 310;
const int mod = 998244353;
int n, m;

struct Point
{
    ll x, y;
    Point operator+(const Point &t) const
    {
        return {x + t.x, y + t.y};
    }
    Point operator*(const ll &k) const
    {
        return {x * k, y * k};
    }
    bool operator<(const Point &t) const
    {
        if (x == t.x)
            return y < t.y;
        return x < t.x;
    }
};
using Vector = Point;
set<Point> st;
Vector v[3];
ll f[N][N][N];
void add(ll &a, ll b)
{
    a += b;
    if (a >= mod)
        a -= mod;
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 0; i < 3; i++)
        cin >> v[i].x >> v[i].y;
    while(m--)
    {
        ll x, y;
        cin >> x >> y;
        st.insert((Point){x, y});
    }
    f[0][0][0] = 1;
    for (int i = 0; i <= n; i++)
    {
        for (int j = 0; j <= i; j++)
        {
            for (int k = 0; k + j <= i; k++)
            {
                int w = i - j - k;
                Point ed;

                ed = v[0] * (j + 1) + v[1] * k + v[2] * w;
                if (!st.count(ed))
                    add(f[i+1][j+1][k], f[i][j][k]);

                ed = v[0] * j + v[1] * (k + 1) + v[2] * w;
                if (!st.count(ed))
                    add(f[i+1][j][k+1], f[i][j][k]);

                ed = v[0] * j + v[1] * k + v[2] * (w + 1);
                if (!st.count(ed))
                    add(f[i+1][j][k], f[i][j][k]);
            }
        }
    }
    ll ans = 0;
    for (int j = 0; j <= n; j++)
        for (int k = 0; k + j <= n; k++)
            add(ans, f[n][j][k]);
    cout << ans << endl;
    return 0;
}
posted @ 2022-09-04 17:26  hzy0227  阅读(47)  评论(0编辑  收藏  举报