在一个 2×n
2
×
n
的网格内,每一格都有一个蘑菇,第一行第 i
i
格内的蘑菇每分钟长大 ai,第二行第 i
i
格内的蘑菇每分钟长大 bi,Vasya
V
a
s
y
a
从第 1
1
行第 1 列的网格开始走起,每分钟都只能往相邻网格内移动,每一格蘑菇都必须经过一次(不能多于一次),最后不必回到初始位置,问如何规划路线才能使 Vasya
V
a
s
y
a
收获的蘑菇最多。
输入
第一行包含一个整数 n(1≤n≤3×105)
n
(
1
≤
n
≤
3
×
10
5
)
,第二行为 n
n
个整数 a1,a2,⋯,an,第三行为 n
n
个整数 b1,b2,⋯,bn,其中 1≤ai,bi≤106。
1
≤
a
i
,
b
i
≤
10
6
。
因此就是枚举中断往返开始一直往右的点,取最大值,在枚举中间点的时候,每次都需要 O(1)
O
(
1
)
地求出贡献,首先用 dfs
d
f
s
预处理出 “↓→↑→
↓→↑→
” 走法的每个点的系数(从左上角点按照“下上右”的顺序 dfs
d
f
s
就可以得到):
然后从右往左递推一下后半段(先往右到最后,再往左回来的部分)的贡献,首先假设到某个点 i
i
的时候的系数为 x,则后面接着所有点的系数为:
继续算从第 i−2
i
−
2
个点开始右转的贡献:
其中 x−4
x
−
4
为第 i−2
i
−
2
个点上面第二张系数图中对应的系数,对比上一张系数图可以发现,从第 i
i
列到第 n 列所有的系数贡献都减 2
2
,而从第 i−2 到第 i−1
i
−
1
列的贡献需要根据 i
i
的位置进行计算,因此就可以从 n 到 1
1
递推得到从任何一列开始右转的贡献,最终 O(2n) 地枚举转折点取最大值就能得到答案。
构造一个 n
n
行 m 列的矩阵,要求构造矩阵的每一行的异或值为 ai
a
i
,每一列的异或值为 bi
b
i
。
输入
第一行包含两个整数 n,m(2≤n,m≤100)
n
,
m
(
2
≤
n
,
m
≤
100
)
,第二行有 n
n
个整数 a1,a2,⋯,an(0≤ai≤109),第三行有 m
m
个整数 b1,b2,⋯,bm(0≤bi≤109)。
输出
如果可以构造出满足条件的矩阵,第一行输出一个 YES
Y
E
S
,接着输出一个 n×m
n
×
m
的矩阵,要求矩阵的每一格元素 0≤cij≤2×109
0
≤
c
i
j
≤
2
×
10
9
,否则输出 NO
N
O
。
样例
输入
2 3 2 9 5 3 13
输出
YES 3 4 5 6 7 8
输入
3 3 1 7 6 2 15 12
输出
NO
题解
前 n−1
n
−
1
行 m−1
m
−
1
列都填 0
0
,最后一行的前 m−1 列分别填上 b1,b2,⋯,bm−1
b
1
,
b
2
,
⋯
,
b
m
−
1
,最后一列的前 n−1
n
−
1
行分别填上 a1,a2,⋯,an−1
a
1
,
a
2
,
⋯
,
a
n
−
1
,最后根据异或的运算规则,分别从行和列的异或结果计算出第 n
n
行第 m 列的值,如果两次计算得到的值相等,则可以构造出满足条件的矩阵,否则输出 NO
N
O
。
过题代码
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <functional>#include <iomanip>usingnamespacestd;
#define LL long longconstint maxn = 100 + 100;
int n, m;
int a[maxn], b[maxn];
int ans[maxn][maxn];
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 1; i < n; ++i) {
for(int j = 1; j < m; ++j) {
ans[i][j] = 0;
}
}
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
ans[i][m] = a[i];
}
for(int i = 1; i <= m; ++i) {
scanf("%d", b + i);
ans[n][i] = b[i];
}
int tmp = 0;
for(int i = 1; i < n; ++i) {
tmp ^= ans[i][m];
}
ans[n][m] = tmp ^ ans[n][m];
tmp = 0;
for(int i = 1; i <= m; ++i) {
tmp ^= ans[n][i];
}
if(tmp == a[n]) {
printf("YES\n");
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
if(j != 1) {
printf(" ");
}
printf("%d", ans[i][j]);
}
printf("\n");
}
} else {
printf("NO\n");
}
}
return0;
}