[CF321D] Ciel and Flipboard
阿新 • • 發佈:2021-10-18
智商已欠費。
了。
前言
智商題殺我。
題目
講解
\(n\) 為奇數,操作區間長度 \(m=\frac{n+1}{2}\),顯然需要挖掘性質。
假如我們一次操作只會翻轉一行,假設翻轉第 \(i\) 行的某個長度為 \(m\) 的區間,不難發現 \(a_{i,m}\) 一定會被翻轉,如果這一次 \(a_{i,j}(j<m)\) 被翻轉,那麼 \(a_{i,j+m}\) 一定沒有被翻轉,vice versa。
更進一步地,一行中如果翻轉了偶數次,那麼 \(a_{i,j}(j<m)\) 與 \(a_{i,j+m}\) 同號,奇數次則異號。
注意不是對稱!某 \(\rm Rain\) 姓同學因為這個和搬題人“精心”構造的大樣例 \(\rm \color{red}WA\)
當然列也有相同的性質,只不過中間那個點變成了 \(a_{m,i}\) 。
那麼翻轉一個 \(m\times m\) 的矩陣意味著什麼呢?意味著你可以在滿足上述規則的基礎上任意變換!因為它們是線性不相關的!
所以只需要列舉一個軸的正負號,另外一個軸貪心求解即可。
時間複雜度 \(O(2^mm^2)\)。
程式碼
短程式碼完全不能說明題目難度.jpg
//12252024832524 #include <bits/stdc++.h> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 35; const LL INF = 1ll << 60; int n,m; LL a[MAXN][MAXN],ans = -INF; LL Read() { LL x = 0,f = 1; char c = getchar(); while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} int f[MAXN]; void solve() { LL ret = a[m][m]*f[m]; for(int i = 1;i < m;++ i) ret += f[i] * a[m][i] + f[i] * f[m] * a[m][i+m];//中間那一行 for(int i = 1;i < m;++ i) { LL MAX = -INF; for(int sg = -1;sg <= 1;sg += 2) { LL cur = a[i][m]*sg+a[i+m][m]*sg*f[m]; for(int j = 1;j < m;++ j) cur += Abs(a[i][j]+a[i+m][j]*f[j]+a[i][j+m]*sg+a[i+m][j+m]*f[j]*f[m]*sg); MAX = Max(MAX,cur); } ret += MAX; } ans = Max(ans,ret); } void dfs(int x) { if(x == m+1) {solve();return;} f[x] = 1; dfs(x+1); f[x] = -1; dfs(x+1); } int main() { // freopen("taozi.in","r",stdin); // freopen("taozi.out","w",stdout); n = Read(); m = (n+1) >> 1; for(int i = 1;i <= n;++ i) for(int j = 1;j <= n;++ j) a[i][j] = Read(); if(n == 1){Put(Abs(a[1][1]),'\n');return 0;} dfs(1); Put(ans,'\n'); return 0; }