AtCoder Beginner Contest 265 E - Warp

E - Warp

题意:

在一个坐标系中,从原地 ( 0 , 0 ) (0,0) 00出发,一共有 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 n300

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=nab,可表示成 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[n1][a1][b]+f[k]dp[n1][a][b]+f[k]dp[n1][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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值