#include<iostream>
#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;
#define MAXN 3010
#define INF 10086
char s[MAXN][MAXN];
struct node{
int x;
bool operator < (const node &a)const
{
return x>a.x;
}
};//从小到大排序
int a[MAXN];//存储结果
void set_1(int n)
{
for(int i=0;i<n;++i)a[i]=1;
}
signed main()
{
int n,m;
scanf("%d%d",&n,&m);
set_1(n);
// for(int i=0;i<n;++i)
// {
// scanf("%s",s[i]);
// }
for(int i=0;i<n;++i)
{
int j=0;
char ch='0';
while(ch!='\n')
{
if(j==m)
{
break;
}
scanf("%c",&ch);
if(ch!='\n')
{
s[i][j]=ch;
}
else
{
ch='0';
continue;
}
++j;
}
}//读取输入
for(int i=0;i<n;++i)
{
priority_queue<node> ttmp;//开优先队列,因为调换操作可以进行无数次,直接取最好情况比较
for(int j=0;j<m;++j)
{
node nod;
nod.x=s[i][j]-'a';
ttmp.push(nod);
}
int tmp[MAXN];//优先队列无法直接访问下标,因此多开个数组
for(int j=0;j<m;++j)
{
tmp[j]=ttmp.top().x;
ttmp.pop();
}
for(int j=0;j<n;++j)
{
int rec=0;//记录字母相同的位数
if(j==i)continue;//跳过自己
if(tmp[rec]<s[j][rec]-'a')
{
continue;
}
else if(tmp[rec]>s[j][rec]-'a')
{
a[i]=0;
break;
}//先比较第0位(此操作其实好像有点多余()
else
{
while(tmp[rec]==s[j][rec]-'a')
{
rec++;
}
if(tmp[rec]>s[j][rec])//前面几位一样,比较后面不一样的字符
{
a[i]=0;
break;
}
}
}
}
for(int i=0;i<n;++i)
{
printf("%d",a[i]);
}
return 0;
}