CF2045G - X Aura 题解
题面
ICPC 山可以表示为由 \(R\) 行(编号从 \(1\) 到 \(R\) )和 \(C\) 列(编号从 \(1\) 到 \(C\) )组成的网格。位于第 \(r\) 行和第 \(c\) 列的单元格表示为 \((r, c)\) ,高度为 \(H_{r, c}\) 。如果两个单元格共享一条边,那么它们就是相邻的。形式上, \((r, c)\)$$ 与 \((r-1, c)\) 、 \((r+1, c)\) 、 \((r, c-1)\) 和 \((r, c+1)\) (如果存在的话)相邻。
您只能在相邻单元格之间移动,每次移动都会受到惩罚。在正奇数 \(X\) 的光环下,从高度为 \(h_1\) 的单元格移动到高度为 \(h_2\) 的单元格会受到 \((h_1 - h_2)^X\) 的惩罚。注意,惩罚值可以是负数。
您希望回答 \(Q\) 个独立的问题。在每个情境中,您从起始单元格 \((R_s, C_s)\) 开始,希望以最小的总罚分到达终点单元格 \((R_f, C_f)\) 。在某些情况下,总罚分可能会变得非常小,这种情况称为无效。请找出从起始单元格移动到目的地单元格的最小总罚分,或确定该方案是否无效。
题解
又是神题,首先考虑什么时候不合法,必然是存在一个环上的权不为 \(0\),如果环权为正,可以倒着走,这样就可以变得无穷小,所以我们需要考虑什么时候不存在环的权非零。
这个问题可以转化为所有 \(2 \times 2\) 的环的权都为零,不妨考虑全部 \(2 \times 2\) 的环权值都为 \(0\),两个有交的环有一条公共边,这条公共边可以由其中一个环的 \(3\) 条边表示,如此反复,可以发现所有的 \(2 \times 2\) 环可以构成任意的环,所以我们只需验证所有的 \(2 \times 2\) 环权值为 \(0\) 即可。
考虑求解答案,由于所有的环权值为 \(0\),那就说明任意两点的距离一定为定值,因此如果要求 \(d(x_1, y_1, x_2, y_2)\),就相当于求 \(d(1, 1, x_2, y_2) - d(1, 1, x_1, y_1)\) 的值,这个 \(d\) 是可以预处理的,因此本题可以在 \(O(NM)\) 的复杂度解决。
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1010;
int n, m, x, q;
int a[N][N];
ll dist[N][N];
int calc(int x1, int y1, int x2, int y2) {return pow(a[x1][y1] - a[x2][y2], x);}
int check()
{
int pd = 0;
for (int i = 1; i < n; i ++ )
for (int j = 1; j < m; j ++ )
if (calc(i, j, i + 1, j) + calc(i + 1, j, i + 1, j + 1) +
calc(i + 1, j + 1, i, j + 1) + calc(i, j + 1, i, j))
pd = 1;
if (!pd) return 0;
for (int i = 1; i <= q; i ++ ) cout << "INVALID\n";
return 1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> x;
char c;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> c, a[i][j] = c - '0';
cin >> q;
if (check()) return 0;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
if (j == 1 && i != 1) dist[i][j] = dist[i - 1][j] + calc(i - 1, j, i, j);
else dist[i][j] = dist[i][j - 1] + calc(i, j - 1, i, j);
while (q -- )
{
int s1, s2, t1, t2;
cin >> s1 >> s2 >> t1 >> t2;
cout << dist[t1][t2] - dist[s1][s2] << "\n";
}
return 0;
}