P13114

被 wisdua 秒了。

in Luogu


其实并非困难。

考虑直接暴力定义 \(dp_{i,j,x,y}\) 表示左上角为 \((j,y)\) 右下角为 \((i,x)\) 的矩阵的 SG 值。转移就是考虑我每一次删掉哪行或者那列。但是这样我们在每次转移的时候还要花 \(\mathrm O(n)\) 的时间去判断能否转移。那么此时考虑对于每一个点去维护在你上面的点中,离你最近的障碍的距离。那么这样我们就可以 \(\mathrm O(n+m)\) 的时间内完成所有的转移。总的复杂度为 \(\mathrm O(n^5)\)\(n,m\) 同阶)。

cin >> n >> m;
for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)cin >> ch[i][j];
for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)U[i][j] = (ch[i][j] == '#' ? 0 : U[i - 1][j] + 1);
for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)L[i][j] = (ch[i][j] == '#' ? 0 : L[i][j - 1] + 1);
memset(dp,0,sizeof(dp));
for(int i = n;i >= 1;i--)
{
    for(int j = i;j <= n;j++)
    {
        for(int x = m;x >= 1;x--)
        {
            for(int y = x;y <= m;y++)
            {
                memset(cnt,0,sizeof(cnt));
                for(int p = i;p <= j;p++)if(L[p][y] >= y - x + 1)cnt[dp[i][p - 1][x][y] ^ dp[p + 1][j][x][y]]++;
                for(int p = x;p <= y;p++)if(U[j][p] >= j - i + 1)cnt[dp[i][j][x][p - 1] ^ dp[i][j][p + 1][y]]++;
                while(cnt[dp[i][j][x][y]])dp[i][j][x][y]++;
            }
        }
    }
}
int ans = 0;
for(int i = 1;i <= n;i++)if(L[i][m] >= m)ans += !(dp[1][i - 1][1][m] ^ dp[i + 1][n][1][m]) * m;
for(int i = 1;i <= m;i++)if(U[n][i] >= n)ans += !(dp[1][n][1][i - 1] ^ dp[1][n][i + 1][m]) * n;
cout << "Case #" << P << ": " << ans << '\n';
posted @ 2025-08-05 21:42  sqrtqwq  阅读(31)  评论(0)    收藏  举报