AtCoder Beginner Contest 232(E,F补题)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 232(E,F补题)相关的知识,希望对你有一定的参考价值。
E - Rook Path
题意:
给定大小为 H × W H×W H×W的矩阵,你现在有一个车(在矩阵可以朝着一个方向走任意距离),现在起点为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),终点 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),你现在只可以恰好移动 k k k次,问从起点移动到终点的方案数为多少?
思路:
对于横和纵分别定义一个
d
p
dp
dp方程,把一个二维的移动看成两个一维的移动,分别定义为
X
(
i
,
0
/
1
)
,
Y
(
i
,
0
/
1
)
X(i,0/1),Y(i,0/1)
X(i,0/1),Y(i,0/1)
以
X
(
i
,
0
/
1
)
X(i,0/1)
X(i,0/1)为例,代表移动了
i
i
i次后,是否到达了终点的方案数(只考虑
x
x
x轴),
0
0
0代表未到达,
1
1
1代表到达了
那么此时状态转移方程
X
(
i
,
1
)
=
X
(
i
−
1
,
0
)
X(i,1)=X(i-1,0)
X(i,1)=X(i−1,0)
X
(
i
,
0
)
=
X
(
i
−
1
,
0
)
×
(
n
−
2
)
+
X
(
i
−
1
,
1
)
×
(
n
−
1
)
X(i,0)=X(i-1,0)×(n-2)+X(i-1,1)×(n-1)
X(i,0)=X(i−1,0)×(n−2)+X(i−1,1)×(n−1)
Y
Y
Y同理
最后就是遍历所有的
X
(
i
,
1
)
和
Y
(
k
−
i
,
1
)
X(i,1)和Y(k-i,1)
X(i,1)和Y(k−i,1),把两个一维的方案相乘,再乘上一个组合数
C
k
i
C^i_k
Cki,来确定这两个一维方案的移动顺序
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
#define ll long long
int n, m, k, X1, Y1, X2, Y2;
ll x[N][2], y[N][2], fact[N], infact[N];
ll qmi(int a, int k, int p)
ll res = 1;
while (k)
if (k & 1) res = (ll)res * a % p;
k >>= 1;
a = (ll)a * a % p;
return res;
void Init()
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i++)
fact[i] = (ll)fact[i - 1] * i % mod;
infact[i] = (ll)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
ll C(int a, int b)
if (a < b) return 0;
return fact[a] * infact[b] % mod * infact[a - b] % mod;
int main()
Init();
scanf("%d%d%d", &n, &m, &k);
scanf("%d%d%d%d", &X1, &Y1, &X2, &Y2);
if (X1 != X2)
x[0][0] = 1;
else
x[0][1] = 1;
if (Y1 != Y2)
y[0][0] = 1;
else
y[0][1] = 1;
for (int i = 1; i <= k; i++)
(x[i][1] += x[i - 1][0]) %= mod;
x[i][0] += (x[i - 1][1] * (n - 1) % mod + x[i - 1][0] * (n - 2) % mod) % mod;
x[i][0] %= mod;
(y[i][1] += y[i - 1][0]) %= mod;
y[i][0] += (y[i - 1][1] * (m - 1) % mod + y[i - 1][0] * (m - 2) % mod) % mod;
y[i][0] %= mod;
ll res = 0;
for (int i = 0; i <= k; i++)
ll temp = x[i][1] * y[k - i][1] % mod;
res += temp * C(k, i) % mod;
res %= mod;
printf("%lld\\n", res);
F - Simple Operations on Sequence
题意:
给定两个长度为
N
N
N的
A
A
A序列和
B
B
B序列,现在有
2
2
2种操作
1.
1.
1.使得
A
i
A_i
Ai增加
1
1
1或者减少
1
1
1,需要消耗
X
X
X元
2.
2.
2.交换
A
i
A_i
Ai和
A
i
+
1
A_i+1
Ai+1的位置,需要消耗
Y
Y
Y元
可以操作多次,问最少花费多少才能使
A
A
A序列变成
B
B
B序列
思路:
序列长度很小,仅为
18
18
18,所以可以考虑状态压缩
假设现在
A
A
A序列中的数有
i
i
i个已经确定,变成
B
B
B中的前
i
i
i个,当然也可以倒过来,是等效的。
那么现在如何表示
A
A
A中哪
i
i
i个数已经确定下来了,就是通过二进制,也就是状态压缩,通过二进制中的
1
1
1的位置,来表示哪些数已经被确定下来了。那么此时只需要枚举,接下来确定那个数即可,且这个数在当前状态下不能被确定过,此时枚举的就是第
i
+
1
i+1
i+1个数,那么此时的代价就是
∣
A
[
i
+
1
]
−
B
[
j
]
∣
×
X
+
c
n
t
×
Y
|A[i+1]-B[j]|×X+cnt×Y
∣A[i+1]−B[j]∣×X+cnt×Y,
c
n
t
cnt
cnt就是把
B
j
B_j
Bj移动到
A
i
+
1
A_i+1
Ai+1位置所需要交换的次数。
所以假设状态就是
s
t
a
t
e
state
state,
c
n
t
S
cntS
cntS为确定数的个数,枚举的数是
B
j
B_j
Bj,
c
n
t
cnt
cnt是把
f
(
s
t
a
t
e
∣
1
<
<
(
j
−
1
)
)
=
m
i
n
(
f
(
s
t
a
t
e
∣
1
<
<
(
j
−
1
)
)
,
f
(
s
t
a
t
e
)
+
∣
A
[
i
+
1
]
−
B
[
j
]
∣
×
X
+
c
n
t
×
Y
)
f(state|1<<(j-1))=min(f(state|1<<(j-1)),f(state)+|A[i+1]-B[j]|×X+cnt×Y)
f(state∣1<<(j−1))=min(f(state∣1<<(j−1)),f(state)+∣A[i+1]−B[j]∣×AtCoder Beginner Contest 234
AtCoder Beginner Contest 115 题解