Problem:
Problem D:
Off Balance
You are working for an administration office of the International
Center for Picassonian Cubism (ICPC), which plans to build a new art
gallery for young artists.  The center is organizing an architectural
design competition to find the best design for the new building.
Submitted designs will look like a screenshot of a well known
game as shown below.
This is because the center specifies that 
the building should be constructed by stacking regular units
called
pieces
, each of which consists of four cubic blocks.
In addition, the center requires the competitors to submit designs
that satisfy the following restrictions.
All the pieces are aligned.  When two pieces touch each other, the faces of
the touching blocks must be placed exactly at the same position.
All the pieces are stable.  Since pieces are merely stacked, 
their centers of masses must be carefully positioned so as not to 
collapse.
The pieces are stacked in a tree-like form 
in order to symbolize boundless potentiality of young artists.
In other words, one and only one
piece touches the ground, and each of other pieces touches one and
only one piece on its bottom faces.
The building has a flat shape.
  This is because the construction site
  is a narrow area located between a
  straight moat and an expressway where 
  no more than one block can be placed 
   between the moat and the
expressway as illustrated below.
It will take many days to fully check stability of designs as it requires 
complicated structural calculation.
Therefore, you are
asked to quickly check obviously unstable designs by focusing on 
centers of masses.  The rules of your quick check are as follows.
Assume the center of mass of a block is located at the center of the
block, and all blocks have the same weight.  
We denote a location of a block by
xy
-coordinates of its
left-bottom corner.  The unit length is the edge length of a block.
Among the blocks of the piece that touch another piece or the ground on their
bottom faces, let
x
L
be the leftmost
x
-coordinate of 
the leftmost block, and let
x
R
be the rightmost
x
-coordinate of the rightmost block.
Let the
x
-coordinate of its accumulated center of mass of
the piece be
M
, where the accumulated center of mass of a piece
P
is the center of the mass of the pieces that are directly and indirectly 
supported by
P
, in addition to
P
itself.  Then the piece is
stable, if and only if
x
L
<
M
<
x
R
.  Otherwise, it is
unstable.  A design of a building is unstable if any of its pieces is unstable.
Note that the above rules could  judge some designs to be unstable even 
if it would not collapse in reality.  For example, the left one of the
following designs shall be judged to be unstable.
Also note that the rules judge boundary cases to be unstable.  For example, the top piece in the above right design has its center of mass exactly above the right end of the bottom piece.  This shall be judged to be unstable.
Write a program that judges stabilit
...(truncated)

Submitted solutions:

code_snippet: #include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define Inf 1000000000

struct dsu {
	public:
	dsu() : _n(0) {}
	explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

	int merge(int a, int b) {
		assert(0 <= a && a < _n);
		assert(0 <= b && b < _n);
		int x = leader(a), y = leader(b);
		if (x == y) return x;
		if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
		parent_or_size[x] += parent_or_size[y];
		parent_or_size[y] = x;
		return x;
	}

	bool same(int a, int b) {
		assert(0 <= a && a < _n);
		assert(0 <= b && b < _n);
		return leader(a) == leader(b);
	}

	int leader(int a) {
		assert(0 <= a && a < _n);
		if (parent_or_size[a] < 0) return a;
		return parent_or_size[a] = leader(parent_or_size[a]);
	}

	int size(int a) {
		assert(0 <= a && a < _n);
		return -parent_or_size[leader(a)];
	}

	std::vector<std::vector<int>> groups() {
		std::vector<int> leader_buf(_n), group_size(_n);
		for (int i = 0; i < _n; i++) {
			leader_buf[i] = leader(i);
			group_size[leader_buf[i]]++;
		}
		std::vector<std::vector<int>> result(_n);
		for (int i = 0; i < _n; i++) {
			result[i].reserve(group_size[i]);
		}
		for (int i = 0; i < _n; i++) {
			result[leader_buf[i]].push_back(i);
		}
		result.erase(
			std::remove_if(result.begin(), result.end(),
						   [&](const std::vector<int>& v) { return v.empty(); }),
			result.end());
		return result;
	}

	private:
	int _n;
	// root node: -1 * component size
	// otherwise: parent
	std::vector<int> parent_or_size;
};

void Unite(vector<string> s,dsu &D){
	int h = s.size(),w = s[0].size();
	vector<int> dx = {1,-1,0,0},dy = {0,0,1,-1};
	
	rep(i,h){
		rep(j,w){
			if(isdigit(s[i][j])){
				rep(k,4){
					int y = i+dy[k],x = j+dx[k];
					if(y<0||y>=h||x<0||x>=w)continue;
					if(s[i][j]==s[y][x]){
						D.merge(i*w+j,y*w+x);
					}
				}
			}
		}
	}	
}

void Unite2(vector<string> s,dsu &D){
	int h = s.size(),w = s[0].size();
	vector<int> dx = {1,-1,0,0},dy = {0,0,1,-1};
	
	rep(i,h){
		rep(j,w){
			if(isdigit(s[i][j])){
				rep(k,4){
					int y = i+dy[k],x = j+dx[k];
					if(y<0||y>=h||x<0||x>=w)continue;
					if(s[i][j]==s[y][x]){
						D.merge(i*w+j,y*w+x);
					}
				}
				if(i==h-1){
					D.merge(i*w+j,h*w);
				}
				else{
					if(isdigit(s[i+1][j])){
						D.merge(i*w+j,(i+1)*w+j);
					}
				}
			}
		}
	}	
}

int main(){
	
	while(true){
		int w,h;
		cin>>w>>h;
		
		if(w==0)break;
		
		vector<string> s(h);
		rep(i,h){
			cin>>s[i];
		}
		
		dsu D(w*h+1);
		Unite(s,D);
		
		bool f = true;
		
		auto ret = D.groups();
		
		rep(i,ret.size()){
			if(ret[i].size()!=4)continue;
			
			auto ss = s;
			int mini = Inf,maxi = -Inf;
			int sum = 0,cnt = 0;
			rep(j,ret[i].size()){
				int t = ret[i][j];
				int y = t/w,x = t%w;
				ss[y][x] = '.';
				if(y==h-1 || (isdigit(s[y+1][x])&&s[y+1][x]!=s[y][x])){
					mini = min(mini,x);
					maxi = max(maxi,x);
				}
				cnt++;
				sum += x*2+1;
				//cout<<y<<','<<x<<"  ";
			}
			//cout<<endl;
			dsu DD(h*w+1);
			Unite(ss,DD);
			Unite2(ss,DD);
			
			rep(j,h){
				rep(k,w){
					if(isdigit(ss[j][k])&&!DD.same(h*w,j*w+k)){
						cnt ++;
						sum += k*2 + 1;
					}
				}
			}
			if(cnt==0)continue;
			mini *= 2;
			maxi ++;
			maxi *= 2;
			mini *= cnt;
			maxi *= cnt;
			
			if(mini < sum && sum < maxi)continue;
			f=false;
			break;
			
		}
		
		if(f)cout<<"STABLE"<<endl;
		else cout<<"UNSTABLE"<<endl;
		
	}
	
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3136
final_rank: 11

code_snippet: #include<bits/stdc++.h>
#define rep(i,a,...) for(int i = (a)*(strlen(#__VA_ARGS__)!=0);i<(int)(strlen(#__VA_ARGS__)?__VA_ARGS__:(a));++i)
#define per(i,a,...) for(int i = (strlen(#__VA_ARGS__)?__VA_ARGS__:(a))-1;i>=(int)(strlen(#__VA_ARGS__)?(a):0);--i)
#define foreach(i, n) for(auto &i:(n))
#define pii pair<int, int>
#define pll pair<long long, long long>
#define all(x) (x).begin(), (x).end()
#define bit(x) (1ll << (x))
using ll = long long;
//const ll MOD = (ll)1e9+7;
const ll MOD = 998244353;
const int INF = (ll)1e9+7;
const ll INFLL = (ll)1e18;
using namespace std;
template<class t>
using vvector = vector<vector<t>>;
template<class t>
using vvvector = vector<vector<vector<t>>>;
template<class t>
using priority_queuer = priority_queue<t, vector<t>, greater<t>>;
template<class t, class u> bool chmax(t &a, u b){if(a<b){a=b;return true;}return false;}
template<class t, class u> bool chmin(t &a, u b){if(a>b){a=b;return true;}return false;}
#ifdef DEBUG
#define debug(x) cout<<"LINE "<<__LINE__<<": "<<#x<<" = "<<x<<endl;
#else
#define debug(x) (void)0
#endif

namespace templates{
  ll modpow(ll x, ll b){
    ll res = 1;
    while(b){
      if(b&1)res = res * x % MOD;
      x = x * x % MOD;
      b>>=1;
    }
    return res;
  }

  ll modinv(ll x){
    return modpow(x, MOD-2);
  }

  bool was_output = false;
  template<class t>
  void output(t a){
    if(was_output)cout << " ";
    cout << a;
    was_output = true;
  }
  void outendl(){
    was_output = false;
    cout << endl;
  }
  ll in(){
    ll res;
    scanf("%lld", &res);
    return res;
  }

  template<class t>
  istream& operator>>(istream&is, vector<t>&x){
    for(auto &i:x)is >> i;
    return is;
  }

  template<class t, class u>
  istream& operator>>(istream&is, pair<t, u>&x){
    is >> x.first >> x.second;
    return is;
  }

  template<class t>
  void in(t&x){
    cin >> x;
  }

  template<class t>
  t in(){
    t res; cin >> res; return res;
  }

  template<class t>
  void out(t x){
    cout << x;
  }

  template<class t>
  vector<t> sorted(vector<t> line,function<bool(t,t)> comp=[](t a,t b){return a<b;}){
    sort(line.begin(),line.end(),comp);
    return line;
  }

  template<class t>
  vector<t> reversed(vector<t> line){
    reverse(line.begin(),line.end());
    return line;
  }
}

using namespace templates;

bool func(int w,int h){
  vvector<int> board(w,vector<int>(h,-1));
  per(y,h){
    rep(x,w){
      char d = in<char>();
      if(d=='.'){
        board[x][y] = -1;
      }else{
        board[x][y] = d - '0';
      }
    }
  }

  map<set<pii>,set<pii>> dp;
  int mx[]={-1,0,1,0};
  int my[]={0,1,0,-1};

  auto isin =
    [&](int x,int y){
      return 0<=min(x,y) and x < w and y < h;
    };

  function<set<pii>(int,int)> get_parents =
    [&](int x,int y){
      int color = board[x][y];
      set<pii> current;
      {
        stack<pii> st;
        current.emplace(x,y);
        st.emplace(x,y);
        while(st.size()){
          pii d = st.top();
          st.pop();
          rep(i,4){
            int nx = mx[i] + d.first;
            int ny = my[i] + d.second;
            if(!isin(nx,ny))continue;
            if(color!=board[nx][ny])continue;;
            if(current.count(pii(nx,ny)))continue;
            current.emplace(nx,ny);
            st.emplace(nx,ny);
          }
        }
      }
      if(dp.count(current)){
        return dp[current];
      }
      set<pii> parents;
      foreach(mino,current){
        int nx = mino.first;
        int ny = mino.second+1;
        if(isin(nx,ny) and color != board[nx][ny] and board[nx][ny] >= 0){
          set<pii> d = get_parents(nx,ny);
          foreach(j,d){
            parents.emplace(j);
          }
        }
        parents.emplace(mino);
      }
      dp[current] = parents;
      return parents;
    };
  function<bool(int,int)> check =
    [&](int x,int y){
      set<pii> current;
      int color = board[x][y];
      {
        stack<pii> st;
        current.emplace(x,y);
        st.emplace(x,y);
        while(st.size()){
          pii d = st.top();
          st.pop();
          rep(i,4){
            int nx = mx[i] + d.first;
            int ny = my[i] + d.second;
            if(!isin(nx,ny))continue;
            if(color!=board[nx][ny])continue;;
            if(current.count(pii(nx,ny)))continue;
            current.emplace(nx,ny);
            st.emplace(nx,ny);
          }
        }
      }
      double left = INF;
      double right = -INF;
      foreach(i,current){
        int nx = i.first;
        int ny = i.second - 1;
        if(ny<0 or (board[nx][ny] != color and board[nx][ny] >= 0)){
          left = min(left,nx-0.5);
          right = max(right,nx+0.5);
        }
      }
      set<pii> parents = get_parents(x,y);
      double sum = 0;
      foreach(i,parents){
        sum += i.first;
      }
      sum /= parents.size();
      left += 1e-5;
      right -= 1e-5;
      return left <= sum and sum <= right;
    };
  rep(x,w){
    rep(y,h){
      if(board[x][y]>=0){
        if(!check(x,y)){
          return false;
        }
      }
    }
  }
  return true;
}

int main(){
  int h;
  int w;
  while(true){
    w = in();
    h = in();
    if(!h or !w)break;
    cout << ((func(w,h))?"STABLE":"UNSTABLE") << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3448
final_rank: 15

code_snippet: #include <queue>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
const vector<int> dx = { 0, 1, 0, -1 };
const vector<int> dy = { 1, 0, -1, 0 };
struct state { int x, y, over; };
const int inf = 1012345678;
int main() {
	int H, W;
	while (cin >> W >> H, H) {
		vector<string> S(H);
		for (int i = 0; i < H; ++i) {
			cin >> S[i];
		}
		bool stable = true;
		for (int i = 0; i < H; ++i) {
			for (int j = 0; j < W; ++j) {
				if (S[i][j] == '.') continue;
				vector<vector<bool> > vis(H, vector<bool>(W));
				vis[i][j] = true;
				deque<state> que;
				que.push_back(state{ i, j, 0 });
				int L = inf, R = -inf, sum = 0, cnt = 0;
				while (!que.empty()) {
					state u = que.front(); que.pop_front();
					sum += u.y;
					++cnt;
					for (int k = 0; k < 4; ++k) {
						int tx = u.x + dx[k], ty = u.y + dy[k];
						if (0 <= tx && tx < H && 0 <= ty && ty < W && !vis[tx][ty] && (S[tx][ty] == S[u.x][u.y] || (k == 3 && S[tx][ty] != '.'))) {
							vis[tx][ty] = true;
							if (S[tx][ty] == S[u.x][u.y]) {
								que.push_front(state{ tx, ty, u.over });
							}
							else {
								que.push_back(state{ tx, ty, u.over + 1 });
							}
						}
						if (u.over == 0 && k == 1 && (tx == H || (S[tx][ty] != '.' && S[tx][ty] != S[u.x][u.y]))) {
							L = min(L, u.y);
							R = max(R, u.y + 1);
						}
					}
				}
				sum = sum * 2 + cnt;
				cnt *= 2;
				if (!(L * cnt < sum && sum < R * cnt)) {
					stable = false;
				}
			}
		}
		cout << (stable ? "STABLE" : "UNSTABLE") << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3172
final_rank: 14

code_snippet: #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> mt;

mt visit;
mt p;
queue<vl> q;
ll w,h;
ll dx[4] = {0, 1, 0, -1};
ll dy[4] = {1, 0, -1, 0};

bool isin(ll x, ll y){
  return x >= 0 && x < w && y >= 0 && y <= h;
}

void show_visit(){
  for(ll i = 0;i <= h;i++){
    for(ll j = 0;j < w;j++){
      cerr << visit[i][j] << " ";
    }
    cerr << endl;
  }
  cerr << endl;
}

int main(){
  while(cin >> w >> h){
    if(w == 0 && h == 0) return 0;
    p = mt(h,vl(w));
    for(ll i = 0;i < h;i++){
      string s;
      cin >> s;
      for(ll j = 0;j < w;j++){
        if(s[j] == '.') p[i][j] = -1;
        else p[i][j] = s[j]-'0';
      }
    }
    p.push_back(vl(w, 0));
    bool flag = true;
    for(ll py = 0;py < h;py++){
      for(ll px = 0;px < w;px++){
        if(p[py][px] == -1) continue;
        visit = mt(h+1,vl(w));
        q = queue<vl>();
        ll xl = w+1,xr = 0;
        visit[py][px] = 1;
        q.push(vl({py, px, p[py][px], 0}));

        ll sum = 0;
        ll block_num = 0;
        while(!q.empty()){
          ll y = q.front()[0];
          ll x = q.front()[1];
          ll block = q.front()[2];
          ll cnt = q.front()[3];
          sum += x;
          block_num++;
          if(cnt == 0){
            if(p[y+1][x] != -1 && p[y+1][x] != block){
              xl = min(xl,x);
              xr = max(xr,x+1);
            }
          }

          q.pop();

          for(ll d = 0;d < 4;d++){
            ll next = x+dx[d];
            ll neyt = y+dy[d];
            if(isin(next, neyt)){
              if(p[neyt][next] == -1) continue;
              if(visit[neyt][next] == 1) continue;
              if(p[neyt][next] == block){
                visit[neyt][next] = 1;
                q.push(vl({neyt, next, p[neyt][next], cnt}));
              }else{
                if(d != 2) continue;
                visit[neyt][next] = 1;
                q.push(vl({neyt, next, p[neyt][next], cnt+1}));
              }
            }
          }



        }
        // show_visit();
        // cerr << sum << " " << xl << " " << xr << endl;
        sum += block_num/2;
        if(sum > xl*block_num && sum < xr*block_num){

        }else{
          flag = false;
        }
      }
    }

    if(flag){
      cout << "STABLE" << endl;
    }else{
      cout << "UNSTABLE" << endl;
    }
  }

}
accuracy: 1
time_ms: 30
memory_kb: 3244
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define ALL(A) A.begin(),A.end()
#define RALL(A) A.rbegin(),A.rend()
typedef long long LL;
typedef pair<int,int> P;
const LL mod=1000000007;
const LL LINF=1LL<<60;
const int INF=1<<30;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
 
 
bool used[100][100];
bool v[100][100];
int xl,xr;
int h,w;
 
 
P rec(int x,int y,bool f,vector<string> s){
    used[y][x]=true;
    if(f){
        v[y][x]=true;
    }
    int r=2*x+1;
    int t=1;
    for (int i = 0; i < 4; i++) {
        int nx=x+dx[i],ny=y+dy[i];
        if(f){
            if(i==1){
                if(s[ny][nx]!=s[y][x]&&s[ny][nx]!='.'){
                    xl=min(xl,x);
                    xr=max(xr,x+1);
                }
            }
        }
        if(0<=nx&&nx<w&&0<=ny&&ny<h){
            if(s[ny][nx]=='.'||used[ny][nx]) continue;
            if(s[y][x]!=s[ny][nx]){
                if(i==3){
                    P p = rec(nx,ny,false,s);
                    r += p.fs;
                    t += p.sc;
                }
            }
            else{
                P p = rec(nx,ny,f,s);
                r += p.fs;
                t += p.sc;
            }
        }
    }
    return mp(r,t);
}
 
 
int main(){
    while(1){
        cin >> w >> h;
        if(!h&&!w) return 0;
        vector<string> s(h);
        memset(v,false,sizeof(v));
        for (int i = 0; i < h; i++) {
            cin >> s[i];
        }
        string k="";
        for (int i = 0; i < w; i++) {
            k.pb('#');
        }
        s.pb(k);
        bool flag=false;
        for (int i = h-1; i >= 0; i--) {
            for (int j = 0; j < w; j++) {
                memset(used,false,sizeof(used));
                if(s[i][j]=='.'||v[i][j]) continue;
                xl=100,xr=0;
                P p = rec(j,i,true,s);
                if(p.fs<=2*xl*p.sc||2*xr*p.sc<=p.fs) flag=true;
            }
        }
        if(flag) puts("UNSTABLE");
        else puts("STABLE");
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3280
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define ALL(A) A.begin(),A.end()
#define RALL(A) A.rbegin(),A.rend()
typedef long long LL;
typedef pair<double,int> P;
const LL mod=1000000007;
const LL LINF=1LL<<60;
const int INF=1<<30;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};


bool used[100][100];
bool v[100][100];
int xl,xr;
int h,w;


P rec(int x,int y,bool f,vector<string> s){
    used[y][x]=true;
    if(f){
        v[y][x]=true;
    }
    double r=x+0.5;
    int t=1;
    for (int i = 0; i < 4; i++) {
        int nx=x+dx[i],ny=y+dy[i];
        if(f){
            if(i==1){
                if(s[ny][nx]!=s[y][x]&&s[ny][nx]!='.'){
                    xl=min(xl,x);
                    xr=max(xr,x+1);
                }
            }
        }
        if(0<=nx&&nx<w&&0<=ny&&ny<h){
            if(s[ny][nx]=='.'||used[ny][nx]) continue;
            if(s[y][x]!=s[ny][nx]){
                if(i==3){
                    P p = rec(nx,ny,false,s);
                    r += p.fs;
                    t += p.sc;
                }
            }
            else{
                P p = rec(nx,ny,f,s);
                r += p.fs;
                t += p.sc;
            }
        }
    }
    return mp(r,t);
}


int main(){
    while(1){
        cin >> w >> h;
        if(!h&&!w) return 0;
        vector<string> s(h);
        memset(v,false,sizeof(v));
        for (int i = 0; i < h; i++) {
            cin >> s[i];
        }
        string k="";
        for (int i = 0; i < w; i++) {
            k.pb('#');
        }
        s.pb(k);
        bool flag=false;
        for (int i = h-1; i >= 0; i--) {
            for (int j = 0; j < w; j++) {
                memset(used,false,sizeof(used));
                if(s[i][j]=='.'||v[i][j]) continue;
                xl=100,xr=0;
                P p = rec(j,i,true,s);
                double M = p.fs/p.sc;
                if(M<=xl||xr<=M) flag=true;
            }
        }
        if(flag) puts("UNSTABLE");
        else puts("STABLE");
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3180
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> l_l;
typedef pair<int, int> i_i;

#define EPS (1e-7)
#define INF (1e9)
#define PI (acos(-1))
//const ll mod = 1000000007;
struct UnionFind {
    vector<int> par;
    vector<int> rank;
    vector<ll> Size;
    UnionFind(int n = 1) {
        init(n);
    }

    void init(int n = 1) {
        par.resize(n + 1); rank.resize(n + 1); Size.resize(n + 1);
        for (int i = 0; i <= n; ++i) par[i] = i, rank[i] = 0, Size[i] = 1;
    }

    int root(int x) {
        if (par[x] == x) {
            return x;
        }
        else {
            int r = root(par[x]);
            return par[x] = r;
        }
    }

    bool issame(int x, int y) {
        return root(x) == root(y);
    }

    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) ++rank[x];
        par[y] = x;
        Size[x] += Size[y];
        return true;
    }

    ll size(int x){
        return Size[root(x)];
    }
};

int W, H;
int field[65][65];
int root;
map<int, int> parent;
map<int, vector<int> > children;
map<int, vector<i_i> > grids;
bool clear;
map<int, int> wsum;
map<int, int> wnum;
void dfs(int from) {
    for(int i = 0; i < grids[from].size(); i++) {
        i_i next = grids[from][i];
        next.first++;
        if(next.first > H) continue;
        if(field[next.first][next.second] == -2) continue;
        if(field[next.first][next.second] == from) continue;
        //if(field[next.first][next.second] == parent[from]) continue;
        if(parent[field[next.first][next.second]] != -1) continue;
        parent[field[next.first][next.second]] = from;
        children[from].push_back(field[next.first][next.second]);
        dfs(field[next.first][next.second]);
    }
    //cerr << from << endl;
    //cerr << "parent: " << parent[from] << endl;
    //cerr << "children: ";
    //for(int i = 0; i < children[from].size(); i++) cerr << children[from][i] << " ";
    //cerr << endl;
}

void dfs2(int from) {
    wsum[from] = 0;
    wnum[from] = 4;
    int wmax = -INF;
    int wmin = INF;
    for(int i = 0; i < grids[from].size(); i++) {
        int wnow = grids[from][i].second;
        int hnow = grids[from][i].first;
        wsum[from] += wnow;
        if(field[hnow-1][wnow] == parent[from] || (parent[from] == -1 && hnow == 1)) wmax = max(wmax, wnow);
        if(field[hnow-1][wnow] == parent[from] || (hnow == 1 && parent[from] == -1)) wmin = min(wmin, wnow);
    }
    for(int i = 0; i < children[from].size(); i++) {
        int to = children[from][i];
        dfs2(to);
        wsum[from] += wsum[to];
        wnum[from] += wnum[to];
    }
    if((wmin - 1) * 2 * wnum[from] >= 2 * wsum[from] - wnum[from] || (wmax * 2) * wnum[from] <= 2 * wsum[from] - wnum[from]) {
        clear = false;
        //cerr << "FAIL: " << from << endl;
    }
    //cerr << from << " " << wnum[from] << " " << wsum[from] << " " << wmin << " " << wmax << endl;
}

UnionFind uni;
int dh[4] = {1, 0, -1, 0};
int dw[4] = {0, 1, 0, -1};

int main() {
    //cout.precision(10);
    cin.tie(0);
    ios::sync_with_stdio(false);
    while(true) {
        clear = true;
        cin >> W >> H;
        if(W == 0) break;
        for(int i = 0; i <= 60000; i++) {
            children[i].clear();
            parent[i] = -1;
            grids[i].clear();
        }
        for(int h = 1; h <= 61; h++) {
            for(int w = 1; w <= W; w++) field[h][w] = 0;
        }
        for(int h = H; h >= 1; h--) {
            string now;
            cin >> now;
            now = "#" + now;
            for(int i = 1; i <= W; i++) field[h][i] = now[i] - '0';
            /*
            for(int w = 1; w <= W; w++) {
                if(now[w] != '.') grids[field[h][w]].push_back({h, w});
            }
            */
        }
        uni.init(100000);
        for(int h = 1; h <= H; h++) {
            for(int w = 1; w <= W; w++) {
                //cerr << h << " " << w << endl;
                if(field[h][w] == (int)('.' - '0')) continue;
                if(h < H) {
                    if(field[h][w] == field[h+1][w]) uni.merge(h*100+w, h*100+100+w);
                }
                if(w < W) {
                    if(field[h][w] == field[h][w+1]) uni.merge(h*100+w, h*100+w+1);
                }
            }
        }
        for(int h = 1; h <= H; h++) {
            for(int w = 1; w <= W; w++) {
                if(uni.size(h*100+w) == 1) continue;
                field[h][w] = uni.root(h*100+w);
            }
        }
        //cout << (int)('.') << endl;
        for(int h = H; h >= 1; h--) {
            for(int w = 1; w <= W; w++) {
                if(field[h][w] != '.') grids[field[h][w]].push_back({h, w});
                //cerr << field[h][w] << " ";
            }
            //cerr << endl;
        }
        for(int w = 1; w <= W; w++) {
            if(field[1][w] != -2) root = field[1][w];
        }
        //cerr << root << endl;
        dfs(root);
        /*
        for(char a = '0'; a <= '9'; a++) {
            //cerr << a << " " << parent[a] << endl;
        }
        */
        dfs2(root);
        if(clear) cout << "STABLE" << endl;
        else cout << "UNSTABLE" << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 570
memory_kb: 16908
final_rank: 20

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
#include <deque>
#include <utility>
#include <set>
#include <queue>
#include <functional>

#define REP(i, n) FOR(i, 0, n)
#define FOR(i, a, b) for(int i = int(a); i < int(b); ++i)
#define RREP(i, n) RFOR(i, 0, n)
#define RFOR(i, a, b) for(int i = int(b) - 1; i >= int(a); --i)

constexpr double EPS = 1e-7;

using PAIR = std::pair<int, int>;

struct Part {
	char num;
	std::vector<PAIR> p;
};

int dy4[] = { -1,0,1,0 };
int dx4[] = { 0,1,0,-1 };

int w, h;
char mat[63][13];
bool visited[63][13];

Part getPart(int y, int x) {
	if (mat[y][x] == '.') return Part();
	Part res;
	char c = mat[y][x];
	res.num = c;

	std::set<PAIR> set;
	set.insert(PAIR(y, x));
	std::queue<PAIR> que;
	que.push(PAIR(y, x));

	while (!que.empty()) {
		PAIR now = que.front(); que.pop();

		REP(d, 4) {
			int dy = now.first + dy4[d];
			int dx = now.second + dx4[d];
			if (dy < 1 || dy >= h + 1 || dx < 0 || dx >= w) continue;
			if (mat[dy][dx] != c) continue;
			PAIR to(dy, dx);
			if (set.count(to)) continue;
			set.insert(to);
			que.push(to);
		}
	}

	for (auto& p : set) {
		res.p.emplace_back(p);
	}
	return res;
}



signed main() {

	while (true) {
		std::cin >> w >> h;
		if (w == 0 && h == 0) break;
		REP(i, h) REP(j, w) {
			std::cin >> mat[i + 1][j];
			visited[i + 1][j] = false;
		}
		REP(j, w) mat[0][j] = '.', mat[h + 1][j] = '#';

		bool ok = [&] {
			RFOR(i, 1, h + 1) REP(j, w) {
				if (mat[i][j] == '.') continue;
				if (visited[i][j]) continue;

				auto base = getPart(i, j);
				int l = 1000, r = -1;
				for (auto& pos : base.p) {
					int y = pos.first, x = pos.second;
					visited[y][x] = true;
					if (mat[y + 1][x] != '.' && mat[y + 1][x] != base.num) {
						l = std::min(l, x);
						r = std::max(r, x + 1);
					}
				}

				std::set<PAIR> above;
				std::function<void(int,int,bool)> calcAbove = [&](int y, int x, bool clear = true) {
					if (clear) above.clear();
					if (above.count(PAIR(y, x))) return;

					Part part = getPart(y, x);
					for (auto& p : part.p) above.insert(p);

					for (auto & p : part.p) {
						char c = mat[p.first - 1][p.second];
						if (c != part.num && c != '.') {
							calcAbove(p.first - 1, p.second, false);
						}
					}
				};

				calcAbove(i, j, true);
				int sz = above.size();
				int sumx = 0;
				for (auto& p : above) {
					sumx += p.second;
				}
				if (l * 2 * sz >= sumx * 2 + sz || sumx * 2 + sz >= r * 2 * sz) return false;
			}
			return true;
		}();
		std::cout << (ok ? "STABLE" : "UNSTABLE") << "\n";
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 2940
final_rank: 10

code_snippet: #include<bits/stdc++.h>
#define r(i,n) for(int i=0;i<n;i++)
using namespace std;
typedef pair<int,int>P;
string s[66],t[66];
int dy[]={-1,0,0,1};
int dx[]={0,1,-1,0};
int h,cnt,w,used[66][130],sum;
map<int,int>id_sum;
map<int,vector<int> >id_each;
void id_dfs(int y,int x,vector<vector<int> >&a,char X,vector<int>&id_x){
  a[y][x]=cnt;
  id_x.push_back(x);
  used[y][x]=1;
  sum++;
  r(i,4){
    int ny=y+dy[i];
    int nx=x+dx[i];
    if(ny<0||nx<0||ny>=h||nx>=w)continue;
    if(used[ny][nx])continue;
    if(s[ny][nx]==X)id_dfs(ny,nx,a,X,id_x);
  }
}
P get_lr(int y,int x,vector<vector<int> >&a){
  int id=a[y][x];
  int ny=y;
  int l_x=1e8,r_x=-1e8;
  for(;ny<h;ny++){
    int flag=0;
    r(j,w)if(a[ny][j]==id){
      if(ny+1==h||(a[ny+1][j]!=-1&&a[ny+1][j]!=id)){
        l_x=min(l_x,j);
        r_x=max(r_x,j);
      }
      flag++;
    }
    if(!flag)break;
  }
  return P(l_x,r_x);
}
vector<int> get_data(int y,int x,vector<vector<int> >&a){
  int used2[600]={};
  int oy=y,ox=x;
  vector<int>id_x;
  queue<P>q;
  q.push(P(y,x));
  used2[a[y][x]]=1;
  while(!q.empty()){
    P p=q.front();q.pop();
    y=p.first;
    x=p.second;
    r(i,h)r(j,w)if(a[i][j]==a[y][x]){
      if(a[i][j]==a[oy][ox])used[i][j]=1;
      id_x.push_back(j);
      r(k,1){
        int ny=i+dy[k];
        int nx=j+dx[k];
        if(ny<0||nx<0||ny>=h||nx>=w)continue;
        if(a[ny][nx]==-1)continue;
        if(used2[a[ny][nx]])continue;
        used2[a[ny][nx]]=1;
        q.push(P(ny,nx));
      }
    }
  }
  return id_x;
}
signed main(){
  while(cin>>w>>h,w){
    id_sum.clear();
    id_each.clear();
    cnt=0;
    memset(used,0,sizeof(used));
    r(i,h)cin>>s[i];
    vector<vector<int> >a(h,vector<int>(w));
    r(i,h)r(j,w)a[i][j]=-1;
    r(i,h)r(j,w)if(isdigit(s[i][j])){
      if(!used[i][j]){
        vector<int>id_x;
        sum=0;
        id_dfs(i,j,a,s[i][j],id_x);
        id_sum[cnt]=sum;
        id_each[cnt++]=id_x;
      }
    }
    int flag=0;
    memset(used,0,sizeof(used));
    r(i,h)r(j,w)if(isdigit(s[i][j])){
      if(used[i][j])continue;
      P x_lr=get_lr(i,j,a);
      vector<int>v=get_data(i,j,a);
      double X=0,L=x_lr.first,R=x_lr.second;
      r(i,v.size())X+=v[i];
      X/=(double)v.size();
      if(!(L-0.5<X&&X<R+0.5))flag++;
    }
    if(!flag)cout<<"STABLE"<<endl;
    else cout<<"UNSTABLE"<<endl;
  }
}
accuracy: 1
time_ms: 10
memory_kb: 3224
final_rank: 12

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <map>

using namespace std;

int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
int w,h;


struct node{
	vector<int> next;
	vector<pair<int,int> > blocks;
	double gx;
	double left;
	double right;
	int num;
	double weight;
	bool fl;
};

void calc(vector<vector<int> > vec,vector<pair<int,int> > piece,map<pair<int,int>,int> mp,node &kubo,vector<node> &nodes){
	if(kubo.fl==1)return;
	vector<int> interval;
	for(int k=0;k<4;k++){
		if(piece[k].first<h-1){
			if(vec[piece[k].first][piece[k].second]!=vec[piece[k].first+1][piece[k].second]&&vec[piece[k].first+1][piece[k].second]!=0){
				interval.push_back(piece[k].second);
			}
		}
	}
	set<int> st;
	vector<int>	ne;
	for(int k=0;k<4;k++){
		if(piece[k].first>0){
			if(vec[piece[k].first][piece[k].second]!=vec[piece[k].first-1][piece[k].second]&&vec[piece[k].first-1][piece[k].second]!=0){
				if(!st.count(mp[make_pair(piece[k].first-1,piece[k].second)])){
					ne.push_back(mp[make_pair(piece[k].first-1,piece[k].second)]);
					st.insert(mp[make_pair(piece[k].first-1,piece[k].second)]);
				}
			}
		}
	}
	kubo.next = ne;
	if(interval.size()>0){
		sort(interval.begin(),interval.end());
	}else{
		for(int k=0;k<w;k++){
			if(vec[h-1][k]!=0){
				interval.push_back(k);
			}
		}
		sort(interval.begin(),interval.end());
	}
	kubo.left = interval[0]-0.5;
	kubo.right = interval[interval.size()-1]+0.5;
	double sum =0;
	double sum_w = 0;
	if(kubo.next.size()==0){
		for(int k=0;k<4;k++){
			sum += (double)piece[k].second;
			sum_w +=1;
		}
		kubo.weight = sum_w;
		kubo.gx = sum/sum_w;
		kubo.fl = 1;
	return;
	}
	for(int k=0;k<kubo.next.size();k++){
		calc(vec,nodes[kubo.next[k]].blocks,mp,nodes[kubo.next[k]],nodes);
		sum += nodes[kubo.next[k]].weight * nodes[kubo.next[k]].gx;
		sum_w += nodes[kubo.next[k]].weight;
	}
	for(int k=0;k<4;k++){
		sum += (double)piece[k].second;
		sum_w +=1;
	}
	kubo.weight = sum_w;
	kubo.gx = sum/sum_w;
	kubo.fl = 1;
	return;
}



int main(){
	string s;
	while(1){
		cin >> w >> h;
		if(w==0&&h==0)break;
		vector<vector<int> > vec;
		for(int i=0;i<h;i++){
			cin >> s;
			vector<int> vec1;
			for(int j=0;j<w;j++){
				if(s[j]=='.'){
					vec1.push_back(0);
				}else{
					vec1.push_back(s[j]-'0');
				}
			}
			vec.push_back(vec1);
		}
		vector<vector<int> > flag(h,vector<int>(w,0));
		vector<node> nodes;
		int node_num = 0;
		map<pair<int,int>,int > mp;
		for(int i=0;i<h;i++){
			for(int j=0;j<w;j++){
				if(vec[i][j]!=0&&flag[i][j]!=1){
					vector<pair<int,int> > piece;
					queue<pair<int,int> > q;
					q.push(make_pair(i,j));
					piece.push_back(make_pair(i,j));
					flag[i][j]=1;
					mp[make_pair(i,j)] = node_num;
					while(!q.empty()){
						pair<int,int> p;
						p = q.front();
						q.pop();
						for(int k=0;k<4;k++){
							if(p.first+dx[k]<0||p.first+dx[k]>=h||p.second+dy[k]<0||p.second+dy[k]>=w)continue;
							if(flag[p.first+dx[k]][p.second+dy[k]]==0&&vec[p.first+dx[k]][p.second+dy[k]]==vec[p.first][p.second]){
								q.push(make_pair(p.first+dx[k],p.second+dy[k]));
								flag[p.first+dx[k]][p.second+dy[k]] = 1;
								mp[make_pair(p.first+dx[k],p.second+dy[k])] = node_num;
								piece.push_back(make_pair(p.first+dx[k],p.second+dy[k]));
							}
						}
					}
					node kubo;
					kubo.blocks = piece;
					kubo.num = node_num;
					kubo.fl =0;
					nodes.push_back(kubo);
					node_num +=1;
				}
			}
		}
		for(int i=0;i<nodes.size();i++){
			calc(vec,nodes[i].blocks,mp,nodes[i],nodes);
		}
		bool ans = 0;
		for(int i=0;i<nodes.size();i++){
			if(nodes[i].gx>=nodes[i].right||nodes[i].gx<=nodes[i].left){
				ans =1;
			}
		}
		if(ans==0)cout << "STABLE" << endl;
		else cout << "UNSTABLE" << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3096
final_rank: 13

code_snippet: #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
//#include<cctype>
#include<climits>
#include<iostream>
#include<string>
#include<vector>
#include<map>
//#include<list>
#include<queue>
#include<deque>
#include<algorithm>
//#include<numeric>
#include<utility>
#include<complex>
//#include<memory>
#include<functional>
#include<cassert>
#include<set>
#include<stack>
#include<random>

const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef pair<int, int> pii;

int H, W;
string board[100];

vector<pii> getPos(char c, int sy, int sx) {
    vector<pii> ret;
    queue<int> que;
    que.push(sy); que.push(sx);
    ret.emplace_back(sy, sx);
    while (!que.empty()) {
        int y = que.front(); que.pop();
        int x = que.front(); que.pop();
        for (int i = 0; i < 4; i++) {
            int ny = y+dy[i];
            int nx = x+dx[i];
            if (ny < 0 || ny >= H || nx < 0 || nx >= W) continue;
            if (board[ny][nx] == c && find(ret.begin(), ret.end(), pii(ny, nx)) == ret.end()) {
                que.push(ny); que.push(nx);
                ret.emplace_back(ny, nx);
            }
        }
    }
    return ret;
}

bool ok() {
    for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) {
        // c ?????¢???
        char c = board[y][x];
        if (c == '.') continue;
        vector<pii> ps = getPos(c, y, x);
        int xl = 100, xr = -1;
        for (pii p : ps) {
            int y = p.first, x = p.second;
            if (y == H-1) {
                xl = min(xl, 2*x);
                xr = max(xr, 2*x+2);
            } else {
                int ny = y+1;
                if (board[ny][x] != '.' && board[ny][x] != c) {
                    xl = min(xl, 2*x);
                    xr = max(xr, 2*x+2);
                }
            }
        }
        // cerr << c << " : " << xl << "  " << xr << endl;
        // ps ????????????????????????????????¢???
        vector<pii> up = ps;
        while (1) {
            bool finish = true;
            for (pii p : up) {
                int y = p.first, x = p.second;
                if (y==0) continue;
                char tmp = board[y-1][x];
                if (tmp == '.') continue;
                vector<pii> cs = getPos(tmp, y-1, x);
                assert(!cs.empty());
                if (find(up.begin(), up.end(), cs[0]) == up.end()) {
                    finish = false;
                    for (pii pp : cs) up.push_back(pp);
                    break;
                }
            }
            if (finish) break;
        }
        int sum = 0;
        for (pii p : up) {
            sum += 2*p.second+1;
        }
        if (sum <= xl * up.size() || sum >= xr * up.size()) return false;
    }
    return true;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    while (cin >> W >> H) {
        if (H==0 && W==0) break;
        for (int i = 0; i < H; i++) cin >> board[i];
        if (ok()) cout << "STABLE" << endl;
        else cout << "UNSTABLE" << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 680
memory_kb: 3152
final_rank: 19

code_snippet: #include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
typedef complex<double> point;
class piece{
public:
  piece(vector<int> x, vector<int> y, int xr_, int xl_, int id_):
    xr(xr_), xl(xl_), id(id_){
    double gx = 0, gy = 0;
    for (int i = 0; i < x.size(); i++) {
      block.push_back(point(x[i], y[i]));
      gx += x[i] + 0.5;
      gy += y[i] + 0.5;
    }
    gravity = point(gx/x.size(), gy/y.size());
  };
  ~piece(){}
  inline void SetSupport(piece p){support.insert(p);}
  void SetRange(vector<string>& grid);
  inline int GetBlockSize(){return block.size();}
  inline point GetBlock(int id_){return block[id_];}
  inline point GetGrabity(){return gravity;}
  inline set<piece> GetSupport(){return support;}
  inline int GetSupportSize(){return support.size();}
  inline int GetId(){return id;}
  bool IsBalance(){
    double x = gravity.real()*block.size();
    int block_sum = block.size();
    for (piece i: support) {
      x += i.GetGrabity().real()*i.GetBlockSize();
      block_sum += i.GetBlockSize();
    }
    x /= block_sum;
    return (xl + eps < x && x < xr - eps + 1);
  }

  bool operator<(const piece p)const{
    return id < p.id;
  }
  void PrintPiece(){
    std::cout << "id:" << id << std::endl;
    std::cout << "xr:" << xr << " xl:" << xl << std::endl;
    std::cout << "gravity:" << gravity << std::endl;
    for (int i = 0; i < block.size(); i++) {
      std::cout << "block[" << i << "]:" << block[i] << std::endl;
    }
    for (piece i:support) {
      std::cout << "support:" << i.GetId() << std::endl;
    }
    std::cout << std::endl;
  }
  set<piece> support;
private:
  int xr, xl, id;
  point gravity;
  vector<point> block;
};
void piece::SetRange(vector<string>& grid){
  int h = grid.size();
  for (int i = 0; i < block.size(); i++) {
    int px = block[i].real(), py = block[i].imag();
    if(block[i].imag() == h - 1 ||
       (grid[py + 1][px] != '.' &&
        grid[py + 1][px] != grid[py][px])) {
      xr = max(xr, px);
      xl = min(xl, px);
    }
  }
}
void SetIndirectSupport(vector<piece>& vp, piece& p){
  if(p.GetSupportSize() == 0)return;
  set<piece> p_support = vp[p.GetId()].support;
  for (piece i: p_support) {
    //std::cout << p.GetId() << std::endl;
    //p.PrintPiece();
    SetIndirectSupport(vp, vp[i.GetId()]);
    //set<piece> i_support = 
    for (piece j: vp[i.GetId()].support) {
      p.SetSupport(j);
    }
  }
}


bool range(int x, int y, int w, int h){
  if(0 <= x && x < w &&
     0 <= y && y < h)return true;
  return false;
}

int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
void dfs(vector<string>& grid, vector<int>& x,
         vector<int>& y, int px, int py, char c){
  int w = grid[0].size(), h = grid.size();
  x.push_back(px);
  y.push_back(py);
  grid[py][px] = '.';
  for (int i = 0; i < 4; i++) {
    if(!range(px + dx[i], py + dy[i], w, h))continue;
    if(grid[py + dy[i]][px + dx[i]] == c){
      dfs(grid, x, y, px + dx[i], py + dy[i], c);
    }
  }
}

void printGrid(vector<string>& grid){
  for (int i = 0; i < grid.size(); i++) {
    std::cout << grid[i] << std::endl;
  }
  std::cout << std::endl;
}

bool IsSupport(vector<string>& grid, point b){
  if(b.imag() > 0 &&
     grid[b.imag() - 1][b.real()] != '.' &&
     grid[b.imag() - 1][b.real()] != grid[b.imag()][b.real()])
    return true;
  return false;
}
               

int main(int argc, char *argv[]){
  int w, h;
  while(std::cin >> w >> h, w){
    vector<string> grid(h);
    for (int i = 0; i < h; i++) {
      std::cin >> grid[i];
    }
    vector<piece> p;
    int cnt = 0;
    for (int i = h - 1; i >= 0; i--) {
      for (int j = 0; j < w; j++) {
        if(grid[i][j] != '.'){
          vector<int> x, y;
          int xr, xl;
          dfs(grid, x, y, j, i, grid[i][j]);
          p.push_back(piece(x, y, 0, 1e9, cnt));
          cnt++;
        }
      }
      
    }
    for (int i = 0; i < p.size(); i++) {
      for (int j = 0; j < p[i].GetBlockSize(); j++) {
        point b = p[i].GetBlock(j);
        grid[(int)b.imag()][(int)b.real()] = '0' + p[i].GetId();
      }
    }
    for (int i = 0; i < p.size(); i++) {
      p[i].SetRange(grid);
    }
    for (int i = 0; i < p.size(); i++) {
      for (int j = 0; j < p[i].GetBlockSize(); j++) {
        point b = p[i].GetBlock(j);
        if(IsSupport(grid, b)){
          int id = grid[b.imag() - 1][b.real()] - '0';
          p[i].SetSupport(p[id]);
        }
      }
    }
    SetIndirectSupport(p, p[0]);
    //std::cout << w << " " << h << std::endl;
    for (int i = 0; i < p.size(); i++) {
      //p[i].PrintPiece();
      if(!p[i].IsBalance()){
        std::cout << "UNSTABLE" << std::endl;
        break;
      }else if(i == p.size() - 1){
        std::cout << "STABLE" << std::endl;
      }
    }
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1448
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <utility>
#include <algorithm>

using namespace std;
#define MP make_pair
typedef pair<int,int> PII;

int W, H;


void findconnected(int x, int y, vector<string>& vs, vector<vector<bool>>& vis, int n, vector<PII>& res){
  if(x < 0 || W <= x || y < 0 || H <= y || vis[y][x] || vs[y][x] != n) return;
  res.push_back(MP(x,y));
  vis[y][x] = true;
  findconnected(x-1,y,vs,vis,n,res);
  findconnected(x+1,y,vs,vis,n,res);
  findconnected(x,y-1,vs,vis,n,res);
  findconnected(x,y+1,vs,vis,n,res);
}

void findOn(int x, int y, vector<string>& vs, vector<vector<bool>>& vis, vector<PII>& res){
  /*
  if(vis[y][x]) return;
  vis[y][x] = true;
  */
  if(y == 0 || vs[y-1][x] == '.' || vs[y][x] == vs[y-1][x]) return;
  vector<PII> tmp;
  findconnected(x,y-1,vs,vis,vs[y-1][x],tmp);
  for(PII& pii:tmp){
	findOn(pii.first,pii.second,vs,vis,res);
	res.push_back(pii);
  }
}

int main(){
  while(cin>>W>>H,W){
	vector<string> vs(H);
	for(int i=0;i<H;++i) cin >> vs[i];

	bool ans = true;
	vector<vector<bool>> ok(H,vector<bool>(W, false));
	for(int y=H-1;y>=0;--y){
	  for(int x=0;x<W;++x){
		if(vs[y][x] == '.' || ok[y][x]){
		  ok[y][x] = true;
		  continue;
		}
		vector<PII> pos, ons;
		findconnected(x,y,vs,ok,vs[y][x],pos);
		vector<vector<bool>> use = ok;
		int sum = 0;
		double xl = 10000, xr = -1;
		for(PII pii:pos){
		  if(pii.second == H-1 || 
			 vs[pii.second+1][pii.first] != '.' && vs[pii.second][pii.first] != vs[pii.second+1][pii.first])
			xl = min(xl, 1.*pii.first), xr = max(xr, 1.*pii.first);
		  findOn(pii.first,pii.second,vs,use,ons);
		  sum += pii.first;
		}
		
		for(PII& p: ons) sum += p.first;
		double c = sum * 1. / (pos.size() + ons.size());
		xl -= 0.5, xr += 0.5;
		if(c <= xl || xr <= c){
		  ans = false;// cout << c<<","<<x << "," <<y << endl;
		}
	  }
	}
	
	cout << (ans? "STABLE": "UNSTABLE") << endl;
  }
  
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 1228
final_rank: 8

code_snippet: #include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <utility>
using namespace std;

/*
struct UnionFind {
	vector<int> data;
	UnionFind(int v) : data(v, -1) { }
	int root(int x) {
		return data[x] < 0 ? x : (data[x] = root(data[x]));
	}
	bool same(int x, int y) {
		return root(x) == root(y);
	}
	int size(int x) {
		return -data[root(x)];
	}
	void merge(int x, int y) {
		x = root(x), y = root(y);
		if(x != y) {
			if(size(y) > size(x)) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
	}
};
*/

const int INF = (int)1e9;

int W, H; 
char B[60][11];
int Bid[60][10];
vector<int> down;
int num;

void dfs(int i, int j, int num) {
	for(int d = 0; d < 4; ++d) {
		const int dy[4] = { 0, 1, 0, -1 };
		const int dx[4] = { 1, 0, -1, 0 };
		int ny = i + dy[d];
		int nx = j + dx[d];
		if(0 <= ny && ny < H && 0 <= nx && nx < W && B[ny][nx] != '.' && B[i][j] == B[ny][nx] && Bid[ny][nx] == -1) {
			Bid[ny][nx] = num;
			dfs(ny, nx, num);
		}
	}
}

pair<int, int> ground(int id) {
	int L = INF, R = -INF;
	for(int i = 0; i < H; ++i) {
		for(int j = 0; j < W; ++j) {
			if(Bid[i][j] == id && ((i > 0 && Bid[i - 1][j] != -1 && Bid[i][j] != Bid[i - 1][j]) || (i == 0))) {
				L = min(L, j);
				R = max(R, j);
			}
		}
	}
	return make_pair(L, R + 1);
}

double gravity(int id) {
	vector<int> sum(W, 0);
	queue<int> Q;
	Q.push(id);
	while(!Q.empty()) {
		int nextId = Q.front(); Q.pop();
		for(int i = 0; i < H; ++i) {
			for(int j = 0; j < W; ++j) {
				if(Bid[i][j] == nextId) sum[j]++;
			}
		}
		for(int k = 0; k < num; ++k) {
			if(down[k] == nextId) Q.push(k);
		}
	}
	double S = 0;
	int c = 0;
	for(int j = 0; j < W; ++j) {
		S += j * sum[j];
		c += sum[j];
	}
	return S / c + 0.5;
}

int main() {
	ios::sync_with_stdio(false);
	while(true) {
		cin >> W >> H;
		if(W == 0 && H == 0) break;
		for(int i = H - 1; i >= 0; --i) {
			cin >> B[i];
		}
		memset(Bid, -1, sizeof(Bid));
		num = 0;
		for(int i = 0; i < H; ++i) {
			for(int j = 0; j < W; ++j) {
				if(B[i][j] != '.' && Bid[i][j] == -1) {
					Bid[i][j] = num;
					dfs(i, j, num);
					++num;
				}
			}
		}
		
		#if 0
		for(int i = H - 1; i >= 0; --i) {
			for(int j = 0; j < W; ++j) {
				if(Bid[i][j] == -1) cout << '.';
				else cout << Bid[i][j];
			}
			cout << endl;
		}
		#endif
		
		down.assign(num, -2);
		for(int id = 0; id < num; ++id) {
			for(int i = 0; i < H; ++i) {
				for(int j = 0; j < W; ++j) {
					if(Bid[i][j] == id && ((i > 0 && Bid[i - 1][j] != -1 && Bid[i][j] != Bid[i - 1][j]) || (i == 0))) {
						if(i == 0) down[id] = -1;
						else down[id] = Bid[i - 1][j];
					}
				}
			}
			
			// cout << "down[" << id << "] = " << down[id] << endl;
		}
		
		bool ok = true;
		for(int id = 0; id < num; ++id) {
			double gr = gravity(id);
			// cout << "gravity(" << id << ") = " << gravity(id) << endl;
			auto ret = ground(id);
			// cout << "L = " << ret.first << ", R = " << ret.second << endl;
			if(gr <= ret.first || ret.second <= gr) ok = false;
		}
		cout << (ok ? "STABLE":"UNSTABLE") << endl;
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1204
final_rank: 1

code_snippet: #include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
int w,h;
int p[15][80];
int flag[15][80];
int sx,nid;
double x_ave[200];
int dx_min[200],dx_max[200];
int edge[200][200];
int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};

void dfs(int x,int y,int id){
	if(flag[x][y])return;
	flag[x][y]=1;
	x_ave[id]+=(double)x+0.5;
	if(y==0 || (y>0 && p[x][y-1]>=1 && p[x][y-1]!=p[x][y])){
		dx_min[id]=min(dx_min[id],x);
		dx_max[id]=max(dx_max[id],x);
	}
	for(int i=0;i<4;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if(nx<0 || nx>=w || ny<0 || ny>=h)continue;
		if(p[x][y]==p[nx][ny])dfs(nx,ny,id);
	}
	for(int i=0;i<1;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if(nx<0 || nx>=w || ny<0 || ny>=h)continue;
		if(p[x][y]!=p[nx][ny] && flag[nx][ny]==0 && p[nx][ny]>=1){
			nid++;
			edge[id][nid]=1;
			dfs(nx,ny,nid);
		}
	}
}

int main(void){
	while(1){
		scanf("%d %d",&w,&h);
		if(w+h==0)break;
		nid=0;
		memset(p,0,sizeof(p));
		memset(flag,0,sizeof(flag));
		for(int i=0;i<200;i++)dx_min[i]=114;
		memset(dx_max,0,sizeof(dx_max));
		memset(x_ave,0,sizeof(x_ave));
		memset(edge,0,sizeof(edge));
		for(int i=h-1;i>=0;i--){
			string str;
			cin >> str;
			for(int j=0;j<w;j++){
				if(str[j]=='.')p[j][i]=0;
				else{
					p[j][i]=str[j]-'0';
					if(i==0)sx=j;
				}
			}
		}
		dfs(sx,0,0);
		for(int k=0;k<=nid;k++){
			for(int i=0;i<=nid;i++){
				for(int j=0;j<=nid;j++){
					edge[i][j]=max(edge[i][j],edge[i][k]&edge[k][j]);
				}
				edge[i][i]=1;
			}
		}
		bool st=true;
		for(int i=0;i<=nid;i++){
			double all=0.0,cnt=0.0;
			for(int j=0;j<=nid;j++){
				if(edge[i][j])cnt+=1.0,all+=x_ave[j]/4.0;
			}
			all/=cnt;
			if(all<=(double)dx_min[i] || all>=(double)(dx_max[i]+1.0))st=false;
		}
		printf("%s\n",st?"STABLE":"UNSTABLE");
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1388
final_rank: 6

code_snippet: #include <iostream>
#include <complex>
#include <sstream>
#include <string>
#include <algorithm>
#include <deque>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <vector>
#include <set>
#include <limits>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define REP(i, j) for(int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for(int i = (int)(j); i < (int)(k); ++i)
#define P pair<int, int>
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
const int MAX_N = 61;

int my[] = {-1, 1, 0, 0};
int mx[] = {0, 0, 1, -1};

class C{
  public: 
    int cnt, sum, parent;
    double p_xl, p_xr;
    vector<P> cs;
    C(int _p, vector<P> _cs, double _p_xl, double _p_xr){
      parent = _p;
      cs = _cs;
      cnt = (int)(cs.size());
      sum = 0;
      REP(i, cs.size()){
        sum += cs[i].second;
      }
      p_xl = _p_xl;
      p_xr = _p_xr;
    }
    C(){};
};

int W, H;
string f[MAX_N];
vector<C> blocks;
vector< set<int> > children;

void find_block(int y, int x, char c, vector<P> &v){
  f[y][x] = '.';
  v.push_back(P(y, x));
  REP(i, 4){
    int ny = y + my[i], nx = x + mx[i];
    if(ny >= 0 && nx >= 0 && ny < H && nx < W && f[ny][nx] == c)
      find_block(ny, nx, c, v);
  }
}

int find_parent(int now){
  int ret = -1;
  vector<P> cs;
  REP(i, blocks.size()){
    if(i == now) continue;
    REP(j, blocks[now].cs.size()){
      REP(k, blocks[i].cs.size()){
        int now_y = blocks[now].cs[j].first;
        int now_x = blocks[now].cs[j].second;
        int block_y = blocks[i].cs[k].first;
        int block_x = blocks[i].cs[k].second;
        if(now_x == block_x && now_y + 1 == block_y){
          ret = i;
          cs.push_back(P(block_y, block_x));
          //blocks[now].p_xl = 100.0;
          //blocks[now].p_xr = -1.0;
          //REP(j, blocks[i].cs.size()){
            //TODO: 以下のif文で本当に合ってる？
            //if(blocks[i].cs[j].first == block_y){
            //  blocks[now].p_xl = min(blocks[now].p_xl, (double)blocks[i].cs[j].second - 0.5);
            //  blocks[now].p_xr = max(blocks[now].p_xr, (double)blocks[i].cs[j].second + 0.5);
            //}
          //}
          //return i;
        }
      }
    }
  }
  if(ret != -1){
    double xl = 100, xr = -1;
    REP(i, cs.size()){
      xl = min(xl, cs[i].second - 0.5);
      xr = max(xr, cs[i].second + 0.5);
    }
    blocks[now].p_xl = xl;
    blocks[now].p_xr = xr;
  }
  return ret;
  //return -1;
}

void find_children(int now, set<int> &c){
  REP(i, blocks.size()){
    if(blocks[i].parent == now && c.find(i) == c.end()){
      c.insert(i);
      find_children(i, c);
    }
  }
}

bool is_valid_tree(int now){
  int a = blocks[now].sum, b = blocks[now].cnt;
  for(set<int>::iterator it = children[now].begin(); it != children[now].end(); ++it){
    C block = blocks[(*it)];
    a += block.sum;
    b += block.cnt;
  }
  double m = (double)a / b;
  //cout <<now <<" : " <<blocks[now].p_xl <<", " <<m <<", " <<blocks[now].p_xr <<endl;
  return (m > blocks[now].p_xl && m < blocks[now].p_xr ? true : false);
}

int main() {
  while(cin >>W >>H && H){
    blocks.clear();
    REP(i, H) cin >>f[i];
    REP(i, W){
      if(isdigit(f[H - 1][i])){
        vector<P> cs;
        find_block(H - 1, i, f[H - 1][i], cs);
        double xl = 100, xr = -1;
        REP(k, cs.size()){
          if(cs[k].first == H - 1){
            xl = min(xl, cs[k].second - 0.5);
            xr = max(xl, cs[k].second + 0.5);
          }
        }
        C tmp = C(-1, cs, xl, xr);
        blocks.push_back(tmp);
      }
    }
    //REP(i, blocks[0].cs.size()) cout <<blocks[0].cs[i].first <<", " <<blocks[0].cs[i].second <<", " <<blocks[0].p_xl <<", " <<blocks[0].p_xr <<endl;
    for(int i = H - 1; i >= 0; --i){
      for(int j = W - 1; j >= 0; --j){
        if(isdigit(f[i][j])){
          vector<P> cs;
          find_block(i, j, f[i][j], cs);
          blocks.push_back(C(-1, cs, -1, 100));
        }
      }
    }
    FOR(i, 1, blocks.size())
      blocks[i].parent = find_parent(i);
    //REP(i, blocks.size()){
    //  cout <<i <<" : " <<endl;
    //  cout <<"parent = " <<blocks[i].parent <<", xl = " <<blocks[i].p_xl <<", xr = " <<blocks[i].p_xr <<endl;
    //  REP(j, blocks[i].cs.size()) cout <<blocks[i].cs[j].first <<", " <<blocks[i].cs[j].second <<" | ";
    //  cout <<endl;
    //}
    children = vector< set<int> >((int)(blocks.size()));
    FOR(i, 1, blocks.size()) children[0].insert(i);
    FOR(i, 1, blocks.size()) find_children(i, children[i]);
    //REP(i, blocks.size()){
    //  cout <<i <<" : ";
    //  for(set<int>::iterator it = children[i].begin(); it != children[i].end(); ++it) cout <<(*it) <<", ";
    //  cout <<endl;
    //}
    bool isok = true;
    REP(i, blocks.size()){
      if(!is_valid_tree(i)){
        isok = false;
        break;
      }
    }
    cout <<(isok ? "STABLE" : "UNSTABLE") <<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1264
final_rank: 4

code_snippet: #define _USE_MATH_DEFINES
#define INF 0x3f3f3f3f
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <limits>
#include <map>
#include <string>
#include <cstring>
#include <set>
#include <deque>
#include <bitset>
#include <list>
#include <cctype>
#include <utility>
 
using namespace std;
 
typedef long long ll;
typedef pair <int,int> P;
typedef pair <int,P > PP;
 
int tx[] = {0,1,0,-1};
int ty[] = {-1,0,1,0};
 
static const double EPS = 1e-8;

template <class T> class Point{
private:
  T x;
  T y;
public:
  Point(T _x,T _y):x(_x),y(_y){}
  Point():x(0),y(0){}
  T getX() const{
    return x;
  }
  T getY() const{
    return y;
  }

  Point operator-(const Point &p) const{
    return Point(x - p.x, y - p.y);
  }
  Point operator+(const Point &p) const{
    return Point(x + p.x, y + p.y);
  }
  Point operator+(const double num) const{
    return Point(x + num, y + num);
  }
  void operator+=(const Point &p){
    x += p.x;
    y += p.y;
  }
  Point operator/(const T div) const{
    return Point(x / div, y / div);
  }
  void operator/=(const T div){
    x /= div;
    y /= div;
  }
};

class Block{
private:
  vector<Point<double> > cells;
  Point<double> center_of_gravity;
  set<int> children;
  double left,right;
  void _compute_center_of_gravity(){
    Point<double> tmp;
    for(int i=0;i<cells.size();i++){
      tmp += (cells[i] + 0.5);
    }
    if(cells.size() > 0){
      tmp /= cells.size();
    }
    center_of_gravity = tmp;
  }
public:
  Block(const vector<Point<double> >& _cells){
    left = 1000.0;
    right = -1.0;
    cells = _cells;
    _compute_center_of_gravity();
  }
  Point<double> get_center_of_gravity() const{
    return center_of_gravity;
  }
  const vector<Point<double> >& get_cells() const{
    return cells;
  }
  void add_child(int child){
    children.insert(child);
  }
  const set<int>& get_children() const{
    return children;
  }
  double get_left() const{
    return left;
  }
  void set_left(double _left){
    left = min(left,_left);
  }
  double get_right() const{
    return right;
  }
  void set_right(double _right){
    right = max(right,_right);
  }
};


void dfs(char stage[60][10],bool visited[60][10],
	 char root,int sx,int sy,vector<Point<double> >& cells,int W,int H){
  visited[sy][sx] = true;
  cells.push_back(Point<double>(sx,sy));
  for(int i=0;i<4;i++){
    int dx = sx + tx[i];
    int dy = sy + ty[i];
    if(dx < 0 || dy < 0 || dx >= W || dy >= H) continue;
    if(stage[dy][dx] != root) continue;
    if(visited[dy][dx]) continue;
    dfs(stage,visited,root,dx,dy,cells,W,H);
  }
}

vector<Block> make_blocks(char stage[60][10],int W,int H){
  bool visited[60][10];
  memset(visited,false,sizeof(visited));

  vector<Block> blocks;
  for(int y=0;y<H;y++){
    for(int x=0;x<W;x++){
      if(visited[y][x]) continue;
      if(0 <= stage[y][x]-'0'
	 && stage[y][x]-'0' <= 9){
	vector<Point<double> > cells;
	dfs(stage,visited,stage[y][x],x,y,cells,W,H);
	Block block(cells);
	blocks.push_back(block);
      }
    }
  }
  return blocks;
}

void make_children(vector<Block>& blocks,int W,int H){
  for(int parent_block_idx = 0; parent_block_idx < blocks.size(); parent_block_idx++){
    for(int child_block_idx = 0; child_block_idx < blocks.size(); child_block_idx++){
      if(parent_block_idx == child_block_idx) continue;
      for(int parent_cell_idx = 0;parent_cell_idx < blocks[parent_block_idx].get_cells().size();parent_cell_idx++){
	double parent_y = blocks[parent_block_idx].get_cells()[parent_cell_idx].getY();
	double parent_x = blocks[parent_block_idx].get_cells()[parent_cell_idx].getX();

	if(abs((parent_y + 1.0) - (double)H) < EPS){
	  blocks[parent_block_idx].set_left(parent_x);
	  blocks[parent_block_idx].set_right(parent_x + 1.0);
	}

	for(int child_cell_idx = 0;child_cell_idx < blocks[child_block_idx].get_cells().size();child_cell_idx++){
	  double child_y = blocks[child_block_idx].get_cells()[child_cell_idx].getY() + 1.0;
	  double child_x = blocks[child_block_idx].get_cells()[child_cell_idx].getX();
	  
	  if(abs(parent_x - child_x) < EPS 
	     && abs(parent_y - child_y) < EPS){
	    blocks[child_block_idx].set_left(child_x);
	    blocks[child_block_idx].set_right(child_x+1.0);
	    blocks[parent_block_idx].add_child(child_block_idx);
	  }
	}
      }
    }
  }
}

bool check_balance(const vector<Block>& blocks){
  for(int parent_block_idx = 0; parent_block_idx < blocks.size(); parent_block_idx++){
    bool visited[1001];
    memset(visited,false,sizeof(visited));

    Point<double> center_of_gravity;
    int count = 0;

    queue<int> que;
    que.push(parent_block_idx);
    while(!que.empty()){
      int parent = que.front();

      if(visited[parent]) continue;
      visited[parent] = true;

      center_of_gravity += blocks[parent].get_center_of_gravity();
      count++;
      que.pop();
      for(set<int>::iterator it = blocks[parent].get_children().begin();
	  it != blocks[parent].get_children().end();
	  it++){
	que.push(*it);
      }
    }

    if(count > 0){
      center_of_gravity /= (double)count;
      if(blocks[parent_block_idx].get_left() + EPS >= center_of_gravity.getX()
	 || center_of_gravity.getX() >= blocks[parent_block_idx].get_right() - EPS){
	return false;
      }
    }
  }
  return true;
}

int main(){
  int W,H;
  while(~scanf("%d %d",&W,&H)){
    if(W==0 && H==0) break;

    char stage[60][10];
    for(int y=0;y<H;y++){
      string line;
      cin >> line;
      for(int x=0;x<W;x++){
	stage[y][x] = line[x];
      }
    }

    vector<Block> blocks = make_blocks(stage,W,H);
    make_children(blocks,W,H);
    printf("%s\n",check_balance(blocks) ? "STABLE" : "UNSTABLE");
  }
}
accuracy: 1
time_ms: 10
memory_kb: 1236
final_rank: 3

code_snippet: #include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <utility>
#include <functional>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <climits>
#include <cassert>
using namespace std;
inline int toInt(string s) {int v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) {ostringstream sout;sout<<x;return sout.str();}
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef long long ll;
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
const double EPS = 1e-9;
const double PI  = acos(-1.0);

int w,h;

struct piece{
	set<pii> blocks;
	vector<piece*> children;
	int lx,rx;
	piece(set<pii> blocks):blocks(blocks),lx(-1),rx(-1){}

	void construct_tree(vector<piece> &pieces,int index){
		REP(i,pieces.size()){
			if(i==index)continue;
			bool ischild=false;
			for(set<pii>::iterator mb=blocks.begin();mb!=blocks.end();mb++){
				for(set<pii>::iterator ob=pieces[i].blocks.begin();ob!=pieces[i].blocks.end();ob++){
					if(mb->first==ob->first+1&&mb->second==ob->second){
						ischild=true;
						goto found;
					}
				}
			}
			found:
			if(ischild){
				children.push_back(&(pieces[i]));
			}
		}
	}

	void set_x(){
		REP(i,children.size()){
			children[i]->lx=INT_MAX,children[i]->rx=INT_MIN;
			for(set<pii>::iterator it=children[i]->blocks.begin();it!=children[i]->blocks.end();it++){
				if(EXIST(blocks,make_pair(it->first+1,it->second))){
					children[i]->lx=min(children[i]->lx,it->second);
					children[i]->rx=max(children[i]->rx,it->second+1);
				}
			}
		}
	}

	int get_weight_pos(){
		int ret=0;
		for(set<pii>::iterator it=blocks.begin();it!=blocks.end();it++){
			ret+=it->second;
		}
		REP(i,children.size()){
			ret+=children[i]->get_weight_pos();
		}
		return ret;
	}

	int get_total_pieces(){
		int ret=4;
		REP(i,children.size()){
			ret+=children[i]->get_total_pieces();
		}
		return ret;
	}

	double get_center(){
		return (double)get_weight_pos()/get_total_pieces()+0.5;
	}

	bool ok(){
		double center=get_center();
		return lx+EPS<center&&center<rx-EPS;
	}
};

int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
piece construct_piece(vs &pp,int y,int x,vvi &used){
	char c=pp[y][x];
	set<pii> blocks;
	queue<pii> q;
	q.push(make_pair(y,x));
	while(!q.empty()){
		pii p=q.front();q.pop();
		REP(d,4){
			int y=p.first+dy[d];
			int x=p.second+dx[d];
			pii block=make_pair(y,x);
			if(y>=0&&x>=0&&y<h&&x<w&&pp[y][x]==c&&!EXIST(blocks,block)){
				blocks.insert(block);
				q.push(block);
				used[y][x]=1;
			}
		}
	}
	return piece(blocks);
}

int main(){
	while(cin>>w>>h,w|h){
		vs p(h);
		REP(i,h){
			cin>>p[i];
		}
		vector<piece> pieces;
		vvi used(h,vi(w));
		REP(i,h){
			REP(j,w){
				if(p[i][j]!='.'&&!used[i][j]){
					pieces.push_back(construct_piece(p,i,j,used));
				}
			}
		}
		REP(i,pieces.size()){
			pieces[i].construct_tree(pieces,i);
		}
		REP(i,pieces.size()){
			pieces[i].set_x();
		}
		REP(i,pieces.size()){
			if(pieces[i].lx==-1){
				int lx=INT_MAX,rx=INT_MIN;
				for(set<pii>::iterator it=pieces[i].blocks.begin();it!=pieces[i].blocks.end();it++){
					if(it->first==h-1){
						lx=min(lx,it->second);
						rx=max(rx,it->second+1);
					}
				}
				pieces[i].lx=lx;
				pieces[i].rx=rx;
			}
		}
		bool ok=true;
		REP(i,pieces.size()){
			if(!pieces[i].ok()){
				ok=false;
				break;
			}
		}
		cout<<(ok?"STABLE":"UNSTABLE")<<endl;
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1264
final_rank: 4

code_snippet: #include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <complex>
#include <queue>
#include <stack>
#include <string>
#include <cmath>
#include <bitset>

#define rep(i,a) for(int i = 0;i < (a); i++)
#define repi(i,a,b) for(int i = (a); i < (b); i++)
#define repd(i,a,b) for(int i = (a); i >= (b); i--)
#define repit(i,a) for(__typeof((a).begin()) i = (a).begin(); i != (a).end(); i++)
#define all(u) (u).begin(),(u).end()
#define rall(u) (u).rbegin(),(u).rend()
#define UNIQUE(u) (u).erase(unique(all(u)),(u).end())
#define pb push_back
#define mp make_pair
#define INF 1e9
#define EPS 1e-10
#define PI acos(-1.0)

using namespace std;

typedef long long ll;
typedef vector<int> vi;

int w, h;

int dj[] = {-1,0,1,0};
int di[] = {0,1,0,-1};

vector<string> ori;
vector<string> museum;
vector<int> cnt;
vector<vector<bool> > flag;

int bottom;
int xl, xr;

void dfs(int i, int j, char c){
    museum[i][j] = 'A';
    if((i+1<h && museum[i+1][j] != '.' && museum[i+1][j] != c && museum[i+1][j] != 'A') || i==h-1){
        xl = min(xl, j);
        xr = max(xr, j);
        //    cout << xl << ' ' << xr << ' ' << i << ' ' << j <<endl;
    }
    rep(a,4){
        int ti = i + di[a];
        int tj = j + dj[a];

        if(ti>=0 && ti<h && tj>=0 && tj<w && museum[ti][tj]==c) dfs(i+di[a],j+dj[a],c);
    }
}

void centerg(int i, int j){
    cnt[j]++;
    flag[i][j] = true;
    rep(a,4){
        int ti = i + di[a];
        int tj = j + dj[a];
        if(ti<0 || ti>=h || tj<0 || tj>=w) continue;
        if(a!=3 && ori[ti][tj] != ori[i][j]) continue;
        if(!flag[ti][tj] && museum[ti][tj]=='A') centerg(i+di[a],j+dj[a]);
    }
}


bool ison(int i, int j, char c){
    flag[i][j] = true;
    if(i > 0 && museum[i-1][j] != 'A' && museum[i-1][j] != '.' && museum[i-1][j] != c) return true;
    rep(a,4){
        int ti = i + di[a];
        int tj = j + dj[a];
        if(ti >= 0 && ti < h && tj >= 0 && tj < w &&
           !flag[ti][tj] && museum[ti][tj] == c){
               if(ison(ti,tj,c)) return true;
        }
    }
    return false;
}

int main(){
    while(cin>>w>>h,w||h){
        museum.clear();
        museum.resize(h);
        cnt.clear();
        cnt.resize(w);
        xl = 0;
        xr = 0;
        rep(i,h) cin >> museum[i];
        ori = museum;
        /*
          rep(i,h) rep(j,w) if(museum[i][j] != '.'){
          dfs(i,j,museum[i][j]);
          goto soto;
          }
          soto:;
        */
        bool ok = true;
        bool mada = true;
        while(mada){
            mada = false;
            rep(i,h){
                rep(j,w){
                    //cout << i << ' ' << j << endl;
                    bottom = -1;
                    if(museum[i][j]!='.' && museum[i][j]!='A'){
                        flag.resize(h);
                        rep(k,h) flag[k] = vector<bool>(w,false);
                        if(ison(i,j,museum[i][j])){
                            mada = true;
                            flag.clear();
                            continue;
                        }
                        flag.clear();
                        //	cout << "hoge\n";
                        //	rep(a,h)rep(b,w)cout << museum[a][b] << (b==w-1? '\n': ' ');
                        //	cout << endl;
                        xl = 100000000;
                        xr = -1;
                        dfs(i,j,museum[i][j]);
                        //rep(a,h)rep(b,w)cout << museum[a][b] << (b==w-1? '\n': ' ');
                        //	cout << endl;
                        double cgx = 0;
                        
                        cnt.clear();
                        cnt.resize(w);
                        flag.clear();
                        flag.resize(h);
                        
                        rep(k,h) flag[k] = vector<bool>(w,false);
                        centerg(i,j);
                        int sum = 0;
                        rep(k,w){
                            sum += cnt[k];
                            cgx += (k+0.5)*cnt[k];
                        }
                        cgx /= sum;
                        //	cout << sum << ' ' << cgx << ' ' << xl << ' ' << xr << endl;
                        if(cgx<=xl+EPS || cgx+EPS>=xr+1){
                            ok = false;
//                            cout << i << ' ' << j << endl;
                            goto fail;
                        }
                    }
                }
            }
        }
    fail:;
        cout << (ok? "STABLE\n": "UNSTABLE\n");
    } 
}
accuracy: 1
time_ms: 30
memory_kb: 1228
final_rank: 9

code_snippet: #include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <valarray>
#include <vector>

#define EPS 1e-9
#define INF 1070000000LL
#define MOD 1000000007LL
#define fir first
#define foreach(it,X) for(__typeof((X).begin()) it=(X).begin();it!=(X).end();it++)
#define ite iterator
#define mp make_pair
#define rep(i,n) rep2(i,0,n)
#define rep2(i,m,n) for(int i=m;i<(n);i++)
#define pb push_back
#define sec second
#define sz(x) ((int)(x).size())

using namespace std;

struct timer{
	time_t start;
	timer(){start=clock();}
	~timer(){cerr<<1.*(clock()-start)/CLOCKS_PER_SEC<<" secs"<<endl;}
};

typedef istringstream iss;
typedef long long ll;
typedef pair<int,int> pi;
typedef stringstream sst;
typedef vector<int> vi;

int w,h;
char p[70][20];
int n;
int id[70][20];
vector<pi> v[400];
int xsum[400];
int bottom;

int used[70][20];
int dy[]={0,1,0,-1};
int dx[]={1,0,-1,0};
void dfs(int y,int x,char c){
	used[y][x]=1;
	id[y][x]=n;
	v[n].pb(mp(y,x));
	xsum[n] += x;
	if(y==h)bottom=n;
	rep(d,4){
		int ny=y+dy[d],nx=x+dx[d];
		if(!used[ny][nx] && p[ny][nx] == c){
			dfs(ny,nx,c);
		}
	}
}

bool on(int a,int b){
	rep(i,4)rep(j,4){
		if(v[a][i].fir == v[b][j].fir-1 && v[a][i].sec == v[b][j].sec){
			return 1;
		}
	}
	return 0;
}

pi sum(int cur){
	int s=xsum[cur];
	int block=1;
	//cout<<cur<<endl;
	rep(i,n)if(i!=cur && on(i,cur)){
		pi p = sum(i);
		s += p.fir;
		block += p.sec;
	}
	return mp(s,block);
}

int f(int cur){
	int l=INF,r=-INF;
	rep(i,4){
		//cout<<i<<endl;
		int y=v[cur][i].fir,x=v[cur][i].sec;
		if(id[y+1][x] != -1 && id[y+1][x] != cur
		|| y==h){
			l = min(l,x);
			r = max(r,x);
		}
	}
	//cout<<cur<<" : "<<l<<" "<<r<<endl;
	pi p = sum(cur);
	double ave = p.fir /4. / p.sec;
	//cout<<p.fir<<" "<<p.sec<<" "<<ave<<endl;
	if(l - 0.5 + EPS <= ave && ave <= r + 0.5 - EPS)return 1;
	return 0;
}

int main(){
	cin.tie(0);
	ios_base::sync_with_stdio(0);
	
	while(cin>>w>>h && w){
		//cout<<w<<" "<<h<<endl;
		memset(p,0,sizeof(p));
		rep2(i,1,h+1)rep2(j,1,w+1){
			cin>>p[i][j];
		}
		memset(used,0,sizeof(used));
		memset(id,-1,sizeof(id));
		memset(xsum,0,sizeof(xsum));
		n=0;
		rep2(i,1,h+1)rep2(j,1,w+1)if(!used[i][j] && isdigit(p[i][j])){
			//cout<<n<<" : "<<i<<" "<<j<<endl;
			v[n].clear();
			dfs(i,j,p[i][j]);
			n++;
		}
		//cout<<"n: "<<n<<endl;
		//rep(i,n)cout<<xsum[i]<<" ";cout<<endl;
		/*cout<<"--"<<endl;
		rep2(i,1,h+1)rep2(j,1,w+1){
			cout<<id[i][j]<<(j==w?"\n":" ");
		}
		cout<<"--"<<endl;*/
		int ans=1;
		rep(i,n){
			//cout<<i<<endl;
			if(!f(i))ans=0;
		}
		cout<<(ans ? "STABLE":"UNSTABLE")<<endl;
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1220
final_rank: 2