CF1042E Vasya and Magic Matrix
阿新 • • 發佈:2018-09-20
gic none ret pri ring main 但是 namespace template
感覺不會期望。
首先把所有格子按照權值從小到大排一下序,這樣一共有$n * m$個元素,每個元素有三個屬性$x, y, val$。
下文中的下標均為排序後的下標。
這樣子我們就可以推出公式:
$f_i = \frac{1}{k}\sum_{j = 1}^{k}(f_j + (x_j - x_i)^2 + (y_j - y_i)^2)$ $($保證$val_j < val_i$並且這樣的元素一共有$k$個$)$。
暴力轉移是$n^2$的,但是我們可以把這個式子拆開:
$f_i = \frac{1}{k}\sum_{j = 1}^{k}f_j + x_i^2 + y_i^2 + \frac{1}{k}\sum_{j = 1}^{k}x_j^2 + \frac{1}{k}\sum_{j = 1}^{k}y_j^2 - \frac{2x_i}{k}\sum_{j = 1}^{k}x_j - \frac{2y_i}{k}\sum_{j = 1}^{k}y_j$
維護$\sum_{i = 1}^{k}x_i^2$、$\sum_{i = 1}^{k}y_i^2$、$\sum_{i = 1}^{k}y_i$、$\sum_{i = 1}^{k}x_i$、$\sum_{i = 1}^{k}f_i$五個前綴和就可以$O(n)$轉移了。
要註意$val_i$可能為$0$。
加上算逆元的時間一共是$O(nmlogP)$。
Code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedefView Codelong long ll; const int N = 1005; const int M = 1e6 + 5; const ll P = 998244353LL; int n, m, tot = 0; ll a[N][N], f[M]; struct Item { ll x, y, val; } b[M]; bool cmp(const Item &u, const Item &v) { return u.val < v.val; } inline ll fpow(ll x, ll y) { ll res= 1LL; for(; y > 0; y >>= 1) { if(y & 1) res = res * x % P; x = x * x % P; } return res; } inline void up(ll &x, ll y) { x = ((x + y) % P + P) % P; } template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > ‘9‘ || ch < ‘0‘; ch = getchar()) if(ch == ‘-‘) op = -1; for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } int main() { read(n), read(m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { read(a[i][j]); b[++tot].x = 1LL * i, b[tot].y = 1LL * j, b[tot].val = a[i][j]; } int stx, sty, pos; read(stx), read(sty); sort(b + 1, b + 1 + tot, cmp); for(int i = 1; i <= tot; i++) if(b[i].x == stx && b[i].y == sty) { pos = i; break; } ll sumx = 0LL, sumy = 0LL, sumx2 = 0LL, sumy2 = 0LL, sumf = 0LL; int k = 0; for(int i = 1; i <= pos; i++) { for(; b[k].val < b[i].val && k <= pos; k++) { up(sumx, b[k].x), up(sumy, b[k].y); up(sumx2, b[k].x * b[k].x % P), up(sumy2, b[k].y * b[k].y % P); up(sumf, f[k]); } if(k <= 1) continue; ll invK = fpow(k - 1, P - 2); up(f[i], invK * sumf % P); up(f[i], b[i].x * b[i].x % P), up(f[i], b[i].y * b[i].y % P); up(f[i], invK * sumx2 % P), up(f[i], invK * sumy2 % P); up(f[i], -2LL * b[i].x % P * invK % P * sumx % P), up(f[i], -2LL * b[i].y % P * invK % P * sumy % P); } printf("%lld\n", f[pos]); return 0; }
提醒自己:寫快速冪不要把函數名寫成$pow$,因為這樣WA了很多次。
CF1042E Vasya and Magic Matrix