E - Warp
题意:
在一个坐标系中,从原地 ( 0 , 0 ) (0,0) (0,0)出发,一共有 3 种操作,即 ( x + A , y + B ) , ( x + C , y + D ) , ( x + E , y + F ) (x+A,y+B),(x+C,y+D),(x+E,y+F) (x+A,y+B),(x+C,y+D),(x+E,y+F),可以进行 n n n 次操作,其中 n ≤ 300 n\leq 300 n≤300。
有 M M M个点上有障碍物,不可停留在障碍物所在点,询问 n n n 次操作有多少种不同的路径,并对 998244353 998244353 998244353 取模。
题解:
首先,根据 n n n 的大小,我们可以判断可以通过 DP 来解决这道题。
其中 d p [ n ] [ a ] [ b ] [ c ] dp[n][a][b][c] dp[n][a][b][c] 代表一共进行了 n n n 次操作,每种操作分别进行了 a , b , c a,b,c a,b,c次。
由于 c = n − a − b c = n-a-b c=n−a−b,可表示成 d p [ n ] [ a ] [ b ] dp[n][a][b] dp[n][a][b],分别枚举 n , a , b n,a,b n,a,b。
特别的是,若当前位于 ( x , y ) (x,y) (x,y),若操作后的点有障碍物,则不可转移, f [ k ] f[k] f[k] 代表当前是否可转移,0/1。
d p [ n ] [ a ] [ b ] = f [ k ] ∗ d p [ n − 1 ] [ a − 1 ] [ b ] + f [ k ] ∗ d p [ n − 1 ] [ a ] [ b ] + f [ k ] ∗ d p [ n − 1 ] [ a ] [ b ] dp[n][a][b]=f[k]*dp[n-1][a-1][b]+f[k]*dp[n-1][a][b]+f[k]*dp[n-1][a][b] dp[n][a][b]=f[k]∗dp[n−1][a−1][b]+f[k]∗dp[n−1][a][b]+f[k]∗dp[n−1][a][b]
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 998244353;
typedef pair<int, int>P;
int n, m;
vector<P>mov(5);
int main() {
cin >> n >> m;
for (int i = 0; i < 3; i++) {
cin >> mov[i].first >> mov[i].second;
}
set<P>st;
for (int i = 0; i < m; i++) {
int x, y; cin >> x >> y;
st.insert({ x,y });
}
vector<vector<ll>>dp(310,vector<ll>(310));
dp[0][0] = 1;
for (int i = 0; i < n; i++) {
vector<vector<ll>>new_dp(310, vector<ll>(310));
for (ll a = 0; a <= i; a++) {
for (ll b = 0; b <= i; b++) {
ll c = i - a - b;
ll x = a * mov[0].first + b * mov[1].first + c * mov[2].first;
ll y= a * mov[0].second + b * mov[1].second + c * mov[2].second;
for (int k = 0; k < 3; k++) {
if (st.find({ x + mov[k].first,y + mov[k].second }) == st.end()) {
new_dp[a + (k == 0)][b + (k == 1)] += dp[a][b];
new_dp[a + (k == 0)][b + (k == 1)] %= mod;
}
}
}
}
swap(dp, new_dp);
}
ll ans = 0;
for (int a = 0; a <= n; a++) {
for (int b = 0; b <= n; b++) {
ans += dp[a][b];
ans %= mod;
}
}
cout << ans;
return 0;
}