SRM495 Div2 Hard(1000) HexagonPuzzle
トークンを移動可能なマスごとにグループに分ける。あるグループのマス数をcとするとc!の配置が考えられる。実際に可能な配置はc!/2。最後の2枚を除いては好きな位置に配置できるが、最後の2枚の位置を入れ替えることはできない。
#include <string> #include <vector> using namespace std; // Union-Find木 class UnionFind { vector<int>p,r,c; public: UnionFind(int n):p(n,-1),r(n),c(n,1){} int find(int x){return p[x]>=0?p[x]=find(p[x]):x;} void unite(int x,int y){x=find(x),y=find(y); if(x!=y)if(r[x]<r[y])p[x]=y,c[y]+=c[x];else p[y]=x,c[x]+=c[y],r[x]+=r[x]==r[y];} bool same(int x, int y){return find(x)==find(y);} int count(int x){return p[x]<0?c[x]:0;} }; class HexagonPuzzle{public: int theCount( vector <string> board ) { int M = 1000000007; int N = (int)board.size(); UnionFind u(N*N); for ( int y=0; y<N-1; y++ ) for ( int x=0; x<=y; x++ ) if ( board[y ][x ]=='.' && board[y+1][x ]=='.' && board[y+1][x+1]=='.' ) u.unite(y*N+x,(y+1)*N+x ), u.unite(y*N+x,(y+1)*N+x+1); for ( int y=1; y<N-1; y++ ) for ( int x=0; x<y; x++ ) if ( board[y ][x ]=='.' && board[y ][x+1]=='.' && board[y+1][x+1]=='.' ) u.unite(y*N+x, y *N+x+1), u.unite(y*N+x,(y+1)*N+x+1); long long ans = 1; for ( int y=0; y<N; y++ ) for ( int x=0; x<=y; x++ ) { int c = u.count(y*N+x); for ( int i=3; i<=c; i++ ) ans = ans*i%M; } return (int)ans; }};