1308 - Awkward Lights
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1308
問題
ライツアウトで解法があるかどうか調べる。
普通のライツアウトはある点を押すとその点とマンハッタン距離1の点が反転するが、この問題ではその点とマンハッタン距離dの点が反転する。
解法があるなら1、無いなら0を出力せよ。
解法
連立合同方程式。詳しくは、 d:id:sune2:20120127:1327637624
下のソースは一般の連立合同方程式を解くためにいらんことしている。
ソース
int modNorm(int a, int m) { return (a%m+m)%m; } // ax+by=gcd(a,b) int extgcd(int a, int b, int &x, int &y) { int g = a; x = 1; y = 0; if (b) { g = extgcd(b, a%b, y, x); y -= (a/b) * x; } return g; } int invMod(int a, int p) { int x, y; if (extgcd(a,p,x,y) == 1) return (x+p)%p; return 0; } typedef vector<int> vec; typedef vector<vec> mat; bool modGaussElimination(const mat &A, const vec &b, int m, vec &res) { int n = A.size(); mat B(n, vec(n+1)); REP(i,n) REP(j,n) B[i][j] = A[i][j]; REP(i, n) B[i][n] = b[i]; int nowy = 0; REP(x, n) { int pivot = -1; for (int j=nowy; j<n; ++j) if (B[j][x]) { pivot = j;break; } if (pivot == -1) continue; swap(B[nowy], B[pivot]); for (int j=nowy+1; j<n; ++j) { int t = B[j][x] * invMod(B[nowy][x], m) % m; if (t) for (int k=x; k<=n; ++k) B[j][k] = modNorm(B[j][k] - B[nowy][k] * t, m); } nowy++; } res.clear(); for (int y=nowy; y<n; ++y) if (B[y][n]) // rank(A) != rank(A|b) return 0; if (nowy != n) { // rank(A) == rank(A|b) != n // 解が一意でない。ひとつ求める res = vec(n,INF); // INFは任意を表す for (int y=n-1; y>=0; --y) { int x; for (x=y; x<n; ++x) { if (B[y][x]) break; } if (x==n) continue; int sum = B[y][n]; for (int i=x+1; i<n; ++i) { if (res[i] == INF) res[i] = 0; // この時点でres[i]が決まってなかったら0とする sum = modNorm(sum - res[i] * B[y][i], m); } res[x] = sum * invMod(B[y][x], m) % m; } REP(i, n) if (res[i]==INF) res[i] = 0; return 0; } // 解が一意に決まる。普通に後退代入 res.resize(n); for (int x=n-1; x>=0; --x) { int sum = B[x][n]; for (int i=n-1; i>x; --i) { sum = modNorm(sum - res[i] * B[x][i], m); } res[x] = sum * invMod(B[x][x], m) % m; } return 1; } int main() { int m, n, d; while(cin>>m>>n>>d, m||n||d) { bool ba[n][m]; mat A(n*m, vec(n*m)); vec b(n*m); REP(i,n) { REP(j,m) { cin >> ba[i][j]; A[i*m+j][i*m+j] = 1; REP(k,n) { REP(l,m) { int dis = abs(i-k)+abs(j-l); if (dis == d) { A[k*m+l][i*m+j] = 1; } } } b[i*m+j] = ba[i][j]; } } vec x; modGaussElimination(A,b,2,x); cout << (x.size() != 0) << endl; } }