NOI模擬(5.19) JSOID2T2 掃地機器人 (bzoj5318)
阿新 • • 發佈:2019-01-02
掃地機器人
題目背景:
5.19 模擬 JSOI2018D2T2
分析:結論分析 + DP
首先我們來明確兩個結論,對於長寬n, m,令d = gcd(n, m)那麼,
1、我們只需要固定前d步,那麼後面的每d步都應該和前d步是相同的;
2、這d步中有i步向下,d - i步向右,那麼gcd(i, n) == 1,gcd(d - i, m) == 1;
滿足以上兩個條件,那麼一定是一個合法方案,至於證明什麼的很顯然啦啦啦,本寶寶不會啊,神特喵的顯然。我們姑且當做是對的吧······
那麼對於n * m個格子,一定是會走n * m / d輪,每一輪走到的格子是一個(i + 1) * (d - i +1)的矩形,i為向下走的步數,每一輪的矩形的左上角是上一輪的右下角,如果超過右邊界就回到左邊,超過下邊界就回到上邊,那麼考慮如何計算貢獻,對於一個格子,顯然如果要有貢獻,那麼在經過他之前不能經過任何一個有障礙的格子,那麼對於第
Source:
/* created by scarlyw */ #include <cstdio> #include <string> #include <algorithm> #include <cstring> #include <iostream> #include <cmath> #include <cctype> #include <vector> #include <set> #include <queue> #include <ctime> #include <deque> #include <iterator> #include <map> inline char read() { static const int IN_LEN = 1024 * 1024; static char buf[IN_LEN], *s, *t; if (s == t) { t = (s = buf) + fread(buf, 1, IN_LEN, stdin); if (s == t) return -1; } return *s++; } // /* template<class T> inline void R(T &x) { static char c; static bool iosig; for (c = read(), iosig = false; !isdigit(c); c = read()) { if (c == -1) return ; if (c == '-') iosig = true; } for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0'); if (iosig) x = -x; } //*/ const int OUT_LEN = 1024 * 1024; char obuf[OUT_LEN], *oh = obuf; inline void write_char(char c) { if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf; *oh++ = c; } template<class T> inline void W(T x) { static int buf[30], cnt; if (x == 0) write_char('0'); else { if (x < 0) write_char('-'), x = -x; for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48; while (cnt) write_char(buf[cnt--]); } } inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); } /* template<class T> inline void R(T &x) { static char c; static bool iosig; for (c = getchar(), iosig = false; !isdigit(c); c = getchar()) { if (c == -1) return ; if (c == '-') iosig = true; } for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0'); if (iosig) x = -x; } // */ const int MAXN = 50 + 3; const int mod = 998244353; int t, n, m, d; long long ans; char s[MAXN]; int f[MAXN][MAXN], g[MAXN][MAXN]; bool a[MAXN << 1 | 1][MAXN << 1 | 1], ban[MAXN][MAXN]; inline void add(int &x, int t) { ((x += t) >= mod) && (x -= mod); } inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } inline void solve(int p, int q) { int sx = 1, sy = 1; for (int i = 1; i <= p; ++i) for (int j = 1; j <= q; ++j) ban[i][j] = false; // memset(ban, 0, sizeof(ban)); for (int c = 1; c <= n * m / d; ++c) { for (int i = 1; i <= p; ++i) for (int j = 1; j <= q; ++j) f[i][j] = g[i][j] = 0; f[p][q] = 1 - ban[p][q]; for (int i = p; i >= 1; --i) for (int j = q; j >= 1; --j) if (ban[i][j] == false) add(f[i - 1][j], f[i][j]), add(f[i][j - 1], f[i][j]); for (int i = 1; i <= p; ++i) for (int j = 1; j <= q; ++j) ban[i][j] |= a[sx + i - 1][sy + j - 1]; sx += p - 1, ((sx > n) ? (sx -= n) : sx); sy += q - 1, ((sy > m) ? (sy -= m) : sy); g[1][1] = 1 - ban[1][1]; for (int i = 1; i <= p; ++i) for (int j = 1; j <= q; ++j) if (ban[i][j] == false) add(g[i + 1][j], g[i][j]), add(g[i][j + 1], g[i][j]); for (int i = 1; i <= p; ++i) for (int j = 1; j <= q; ++j) if (ban[i][j] == false && (i != p || j != q)) ans = (ans + (long long)f[i][j] * g[i][j]) % mod; } } inline void solve() { R(n), R(m), d = gcd(n, m), ans = 0; for (int i = 1; i <= n; ++i, read()) for (int j = 1; j <= m; ++j) a[i][j] = a[i + n][j] = a[i][j + m] = a[i + n][j + m] = read() - '0'; for (int i = 1; i <= d; ++i) if (gcd(i, n) == 1 && gcd(d - i, m) == 1) solve(i + 1, d - i + 1); std::cout << ans << '\n'; } int main() { // freopen("in.in", "r", stdin); R(t); while (t--) solve(); return 0; }