[USACO23JAN] Following Directions S 题解
思路
这题很简单,预处理加暴力 $O(n)$ 修改维护和 $O(1)$ 查询,总的 $O(n^2 + n \times q)$。
具体的,我们首先一遍计算出一个 $f_{i,j}$ 表示初始有 $f_{i,j}$ 头牛会经过 $(i,j)$ 这个点。并记录 $v_{i,j}$ 表示 $(i,j)$ 这个位置最后会走到多少价格的饲料桶。
然后每次暴力对 $f$ 和 $v$ 两个数组修改即可,记得还要更新那个操作位置的方向。
代码
#include <bits/stdc++.h>
#define ll long long
#define L(i, a, b) for(int i = a; i <= b; i++)
#define R(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
const int N = 1510;
int n, q, c[N][N], v[N][N], f[N][N];
ll ans;
int Upd(int x, int y, int v){//暴力修改f数组
if(x == n + 1 || y == n + 1) return v * c[x][y];
f[x][y] += v;
if(!c[x][y]) return Upd(x, y + 1, v);
else return Upd(x + 1, y, v);
}
int main(){
scanf("%d", &n);
L(i, 1, n){
L(j, 1, n){
char ch; scanf(" %c", &ch);
c[i][j] = (ch == 'D');
}
scanf("%d", &c[i][n + 1]);
}
L(i, 1, n) scanf("%d", &c[n + 1][i]);
L(i, 1, n){
L(j, 1, n){
f[i][j]++;
if(!c[i][j]) f[i][j + 1] += f[i][j];
else f[i + 1][j] += f[i][j];
}
}
R(i, n, 1){
R(j, n, 1){
if(!c[i][j]) v[i][j] = (j == n? c[i][j + 1] : v[i][j + 1]);
else v[i][j] = (i == n? c[i + 1][j] : v[i + 1][j]);
ans += v[i][j];
}
}
printf("%lld\n", ans);
scanf("%d", &q);
L(i, 1, q){
int x, y;
scanf("%d%d", &x, &y);
if(!c[x][y]){
c[x][y] = 1;
ans = ans + Upd(x + 1, y, f[x][y]) + Upd(x, y + 1, -f[x][y]);
}
else{
c[x][y] = 0;
ans = ans + Upd(x, y + 1, f[x][y]) + Upd(x + 1, y, -f[x][y]);
}
printf("%lld\n", ans);
}
return 0;
}