• Warp(DP)


    题意

    有一个人站在二维平面的原点处。

    他将会进行\(N\)次传送,每次传送他可以做如下三种移动中的一种:

    • 从当前位置\((X,Y)\)移动到\((X+A,Y+B)\)
    • 从当前位置\((X,Y)\)移动到\((X+C,Y+D)\)
    • 从当前位置\((X,Y)\)移动到\((X+E,Y+F)\)

    \(M\)个障碍物,分别位于\((X_1,Y_1),\dots, (X_M, Y_M)\),他不能传送到这些点上。

    问经过\(N\)次传送,会产生多少条路径。

    题目链接:https://atcoder.jp/contests/abc265/tasks/abc265_e

    数据范围

    \(1 \leq N \leq 300\)
    \(0 \leq M \leq 10^5\)
    \(-10^9 \leq A,B,C,D,E,F \leq 10^9\)

    思路

    这里提供两种思路。两种思路都是使用DP。

    第一种思路,令\(f(n, x, y)\)表示\(n\)次传送,终点是\((x,y)\)的路径条数,转移方程显然。但是坐标范围太大,真的可以这样做吗?其实能到达的点的数量并不多。我们可以分析一下,三种传送方式的个数决定了终点,并且在给定总次数的情况下,固定前两种传送方式的个数,第三种传送方式的个数也固定了。因此,传送到的点数其实只有\(O(N^2)\)。在实际编写代码的过程中,不能直接使用数组进行转移,可以使用map来做。

    第二种思路,令\(f(n,x,y)\)表示\(n\)次传送,其中第一种传送使用次数为\(x\),第二种传送使用次数为\(y\),可以产生多少条路径。转移方程显然。

    代码

    思路1

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <set>
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<ll, ll> pii;
    
    const int N = 310, M = 100010, mod = 998244353;
    
    int n, m;
    ll dx[5], dy[5];
    map<pii, ll> f;
    set<pii> st;
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < 3; i ++) {
            scanf("%lld%lld", &dx[i], &dy[i]);
        }
        for(int i = 1; i <= m; i ++) {
            ll x, y;
            scanf("%lld%lld", &x, &y);
            st.insert({x, y});
        }
        f[{0, 0}] = 1;
        for(int i = 0; i < n; i ++) {
            map<pii, ll> g;
            for(auto p : f) {
                ll x = p.first.first, y = p.first.second, val = p.second;
                for(int j = 0; j < 3; j ++) {
                    ll tx = x + dx[j], ty = y + dy[j];
                    if(st.find({tx, ty}) != st.end()) continue;
                    g[{tx, ty}] = (g[{tx, ty}] + val) % mod;
                }
            }
            swap(f, g);
        }
        ll res = 0;
        for(auto p : f) {
            res = (res + p.second) % mod;
        }
        printf("%lld\n", res);
        return 0;
    }
    

    思路2

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<ll, ll> pii;
    
    const int N = 310, M = 100010, mod = 998244353;
    
    int n, m;
    ll dx[5], dy[5];
    ll f[N][N][N];
    map<pii, bool> st;
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < 3; i ++) {
            scanf("%lld%lld", &dx[i], &dy[i]);
        }
        for(int i = 1; i <= m; i ++) {
            ll x, y;
            scanf("%lld%lld", &x, &y);
            st[{x, y}] = true;
        }
        f[0][0][0] = 1;
        for(ll i = 1; i <= n; i ++) {
            for(ll j = 0; j <= i; j ++) {
                for(ll k = 0; k <= i; k ++) {
                    ll z = i - j - k;
                    if(z < 0) continue;
                    ll X = j * dx[0] + k * dx[1] + z * dx[2];
                    ll Y = j * dy[0] + k * dy[1] + z * dy[2];
                    if(st.count({X, Y})) {
                        f[i][j][k] = 0;
                        continue;
                    }
                    f[i][j][k] = (f[i - 1][j][k] + f[i - 1][j - 1][k]) % mod;
                    f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1]) % mod;
                }
            }
        }
        ll res = 0;
        for(int i = 0; i <= n; i ++) {
            for(int j = 0; j <= n; j ++) {
                if(i + j > n) continue;
                res = (res + f[n][i][j]) % mod;
            }
        }
        printf("%lld\n", res);
        return 0;
    }
    
  • 相关阅读:
    c 头文件<ctype.h>(一)
    联想M490 开机U盘启动 快捷键
    多文件 定义全局变量的使用 extern
    Unity3D学习笔记(十一):布料和协程
    Unity3D学习笔记(十):Physics类和射线
    Unity3D学习笔记(九):摄像机
    Unity3D学习笔记(八):四元素和书籍推荐
    Unity3D学习笔记(七):叉乘和四元素
    Unity3D学习笔记(六):三角函数和点乘
    Unity3D学习笔记(五):坐标系、向量、3D数学
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/16656632.html
Copyright © 2020-2023  润新知