//experimental template for subs in java//
import java.io.*;
import java.util.*;
import java.lang.Math;
public class template{
	public static void main(String[] arg)throws IOException{

        Reader in = new Reader();
        String s=in.readLine();
        int n=s.length();
        //code goes her-->
        int[][] arr1=new int[26][26];
        for(int i=0;i<n-1;i++){
            for(int j=i;j<n;j++){
                arr1[(int)s.charAt(i)-97][(int)s.charAt(j)-97]++;
            }
        }
        int max=0;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        System.out.println(max);

	}
}
//fast IO

public class Reader
    {
        final public int BUFFER_SIZE = 1 << 16;
        public DataInputStream din;
        public byte[] buffer;
        public int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[100000]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        public void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        public byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


import java.io.*;
import java.util.*;
import java.lang.Math;
public class cowandmessage{
	public static void main(String[] arg)throws IOException{
		Reader in=new Reader();
        String s=in.readLine();
        int n=s.length();

        //code goes here-->
        int[] arr2=new int[26];
        int[][] arr1=new int[26][26];
        for(int i=0;i<n-1;i++){
            arr2[(int)s.charAt(i)-97]++;
            for(int j=i+1;j<n;j++){
                arr1[(int)s.charAt(i)-97][(int)s.charAt(j)-97]++;
            }
        }
        arr2[(int)s.charAt(n-1)-97]++;
        int max=0;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        for(int i=0;i<26;i++){
            if(max<arr2[i]){
                max=arr2[i];
            }

        }
        System.out.println(max);

	}
}
public class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[100000]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


import java.io.*;
import java.util.*;
import java.lang.Math;
public class cowandmessage{
	public static void main(String[] arg)throws IOException{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String s=in.readLine();
        int n=s.length();

        //code goes here-->
        long[] arr2=new long[26];
        long[][] arr1=new long[26][26];
        for(int i=0;i<n;i++){

            for(int j=0;j<26;j++){
                arr1[s.charAt(i)-'a'][j]+=arr2[j];
            }
            arr2[(int)s.charAt(i)-'a']++;

        }

        long max=-1;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        for(int i=0;i<26;i++){
            if(max<arr2[i]){
                max=arr2[i];
            }

        }
        System.out.println(max);

	}
}
class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[100000]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


import java.io.*;
import java.util.*;
import java.lang.Math;
public class cowandmessage{
	public static void main(String[] arg)throws IOException{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String s=in.readLine();
        int n=s.length();

        //code goes here-->
        int[] arr2=new int[26];
        int[][] arr1=new int[26][26];
        for(int i=0;i<n;i++){

            for(int j=0;j<26;j++){
                arr1[j][(int)s.charAt(i)-97]+=arr2[j];
            }
            arr2[(int)s.charAt(i)-97]++;

        }

        int max=0;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        for(int i=0;i<26;i++){
            if(max<arr2[i]){
                max=arr2[i];
            }

        }
        System.out.println(max);

	}
}
class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[100000]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


//experimental template for subs in java//
import java.io.*;
import java.util.*;
import java.lang.Math;
public class cowandmessage{
	public static void main(String[] arg)throws IOException{

        Reader in = new Reader();
        String s=in.readLine();
        int n=s.length();
        //code goes her-->
        int[][] arr1=new int[26][26];
        for(int i=0;i<n-1;i++){
            for(int j=i;j<n;j++){
                arr1[(int)s.charAt(i)-97][(int)s.charAt(j)-97]++;
            }
        }
        int max=0;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        System.out.println(max);

	}
}
//fast IO

class Reader
    {
        final public int BUFFER_SIZE = 1 << 16;
        public DataInputStream din;
        public byte[] buffer;
        public int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[100000]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        public void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        public byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


import java.io.*;
import java.util.*;
import java.lang.Math;
public class cowandmessage{
	public static void main(String[] arg)throws IOException{
		Scanner in=new Scanner(System.in);
        String s=in.nextLine();
        int n=s.length();

        //code goes her-->
        int[][] arr1=new int[26][26];
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                arr1[(int)s.charAt(i)-97][(int)s.charAt(j)-97]++;
            }
        }
        int max=0;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        System.out.println(max);

	}
}
//fast IO


import java.io.*;
import java.util.*;
import java.lang.Math;
public class cowandmessage{
	public static void main(String[] arg)throws IOException{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String s=in.readLine();
        int n=s.length();

        //code goes here-->
        int[] arr2=new int[26];
        int[][] arr1=new int[26][26];
        for(int i=0;i<n;i++){

            for(int j=0;j<26;j++){
                arr1[(int)s.charAt(i)-97][j]+=arr2[j];
            }
            arr2[(int)s.charAt(i)-97]++;

        }

        int max=0;
        for(int i=0;i<26;i++){
            for(int j=0;j<26;j++){
                if(max<arr1[i][j]){
                    max=arr1[i][j];
                }
            }

        }
        for(int i=0;i<26;i++){
            if(max<arr2[i]){
                max=arr2[i];
            }

        }
        System.out.println(max);

	}
}
class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[100000]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }


//
import java.math.*;
import java.util.*;
import java.io.*;

public class C {

    static BufferedReader in;
    static PrintWriter out = new PrintWriter(System.out);
    static String file = "../in";
    static int test = 10; // 0 for local testing, 1 for std input
    static int inf = 1_000_000;

    static void swap(int[]ary, int i, int j)
    {
        int t = ary[i];
        ary[i] = ary[j];
        ary[j] = t;
    }

    static String[] split() throws Exception
    {
        return in.readLine().split(" ");
    }

    static int readInt() throws Exception
    {
        return Integer.valueOf(in.readLine());
    }

    static int[] toIntArray() throws Exception
    {
        String[] sp = split();
        int n = sp.length;
        int[] ary = new int[n];
        for(int i = 0; i < n; i++) ary[i] = Integer.valueOf(sp[i]);
        return ary;
    }

    public static void main(String[] args) throws Exception
    {
        int _k = Integer.valueOf("1");
        if(test > 0) in = new BufferedReader(new InputStreamReader(System.in));
        else in = new BufferedReader(new FileReader(file));
        if(test < 0) {String[] str = in.readLine().split(" ");}

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        String str = in.readLine();

        int n = str.length();
        long maxi = 0L;

        // int[] f = new int[26];

        // // for(char c : str.toCharArray()) {
        // //     f[c - 'a']++;
        // //     maxi = Math.max(maxi, f[c - 'a']);
        // // }

        int[] f = new int[26];
        int[][] g = new int[26][26];

        for(int i = 0; i < n; i++)
        {
            int b = str.charAt(i) - 'a';
            for(int j = 0; j <26; j++)
            {
                g[j][b] += f[j];
                maxi = Math.max(maxi, g[j][b]);
            }
            f[b]++;
            maxi = Math.max(maxi, f[b]);
        }

        out.println(maxi);
        // out.println(map);

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        out.flush();
    }
}


//
import java.math.*;
import java.util.*;
import java.io.*;

public class C {

    static BufferedReader in;
    static PrintWriter out = new PrintWriter(System.out);
    static String file = "../in";
    static int test = 10; // 0 for local testing, 1 for std input
    static int inf = 1_000_000;

    static void swap(int[]ary, int i, int j)
    {
        int t = ary[i];
        ary[i] = ary[j];
        ary[j] = t;
    }

    static String[] split() throws Exception
    {
        return in.readLine().split(" ");
    }

    static int readInt() throws Exception
    {
        return Integer.valueOf(in.readLine());
    }

    static int[] toIntArray() throws Exception
    {
        String[] sp = split();
        int n = sp.length;
        int[] ary = new int[n];
        for(int i = 0; i < n; i++) ary[i] = Integer.valueOf(sp[i]);
        return ary;
    }

    public static void main(String[] args) throws Exception
    {
        int _k = Integer.valueOf("1");
        if(test > 0) in = new BufferedReader(new InputStreamReader(System.in));
        else in = new BufferedReader(new FileReader(file));
        if(test < 0) {String[] str = in.readLine().split(" ");}

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        String str = in.readLine();

        int n = str.length();

        // int[] f = new int[26];

        // // for(char c : str.toCharArray()) {
        // //     f[c - 'a']++;
        // //     maxi = Math.max(maxi, f[c - 'a']);
        // // }

        long[] f = new long[26];
        long[][] g = new long[26][26];

        for(int i = 0; i < n; i++)
        {
            int b = str.charAt(i) - 'a';
            for(int j = 0; j <26; j++)
            {
                g[j][b] += f[j];
            }
            f[b]++;
        }

        long maxi = 0;
        for(int i = 0; i < 26; i++)
        {
            for(int j = 0; j < 26; j++)
            {
                maxi = Math.max(maxi, g[i][j]);
            }
            maxi = Math.max(maxi, f[i]);
        }

        out.println(maxi);

        // out.println(map);

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        out.flush();
    }
}


//
import java.math.*;
import java.util.*;
import java.io.*;

public class C {

    static BufferedReader in;
    static PrintWriter out = new PrintWriter(System.out);
    static String file = "../in";
    static int test = 10; // 0 for local testing, 1 for std input
    static int inf = 1_000_000;

    static void swap(int[]ary, int i, int j)
    {
        int t = ary[i];
        ary[i] = ary[j];
        ary[j] = t;
    }

    static String[] split() throws Exception
    {
        return in.readLine().split(" ");
    }

    static int readInt() throws Exception
    {
        return Integer.valueOf(in.readLine());
    }

    static int[] toIntArray() throws Exception
    {
        String[] sp = split();
        int n = sp.length;
        int[] ary = new int[n];
        for(int i = 0; i < n; i++) ary[i] = Integer.valueOf(sp[i]);
        return ary;
    }

    public static void main(String[] args) throws Exception
    {
        int _k = Integer.valueOf("1");
        if(test > 0) in = new BufferedReader(new InputStreamReader(System.in));
        else in = new BufferedReader(new FileReader(file));
        if(test < 0) {String[] str = in.readLine().split(" ");}

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        String str = in.readLine();

        int n = str.length();
        long maxi = 0L;

        // int[] f = new int[26];

        // // for(char c : str.toCharArray()) {
        // //     f[c - 'a']++;
        // //     maxi = Math.max(maxi, f[c - 'a']);
        // // }

        int[] f = new int[26];
        int[][] g = new int[26][26];

        for(int i = 0; i < n; i++)
        {
            int b = str.charAt(i) - 'a';
            for(int j = 0; j <26; j++)
            {
                g[j][b] += f[j];
                maxi = Math.max(maxi, g[j][b]);
            }
            f[b]++;
            maxi = Math.max(maxi, f[b]);
        }

        if(str.startsWith("jjj")) {
            System.out.println(Arrays.toString(f));
            for(int[] gg : g)
                System.out.println(Arrays.toString(gg));
            System.out.println(str.length());
        }
        out.println(maxi);

        // out.println(map);

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        out.flush();
    }
}


//
import java.math.*;
import java.util.*;
import java.io.*;

public class A {

    static BufferedReader in;
    static PrintWriter out = new PrintWriter(System.out);
    static String file = "../in";
    static int test = 10; // 0 for local testing, 1 for std input
    static int inf = 1_000_000;

    static void swap(int[]ary, int i, int j)
    {
        int t = ary[i];
        ary[i] = ary[j];
        ary[j] = t;
    }

    static String[] split() throws Exception
    {
        return in.readLine().split(" ");
    }

    static int readInt() throws Exception
    {
        return Integer.valueOf(in.readLine());
    }

    static int[] toIntArray() throws Exception
    {
        String[] sp = split();
        int n = sp.length;
        int[] ary = new int[n];
        for(int i = 0; i < n; i++) ary[i] = Integer.valueOf(sp[i]);
        return ary;
    }

    public static void main(String[] args) throws Exception
    {
        int _k = Integer.valueOf("1");
        if(test > 0) in = new BufferedReader(new InputStreamReader(System.in));
        else in = new BufferedReader(new FileReader(file));
        if(test < 0) {String[] str = in.readLine().split(" ");}

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        String str = in.readLine();

        int n = str.length(), maxi = 0;

        int[] f = new int[26];
        for(char c : str.toCharArray()) {
            f[c - 'a']++;
            maxi = Math.max(maxi, f[c - 'a']);
        }

        Map<String, Integer> map = new HashMap<>();

        for(int i = 0; i < n; i++)
        {
            for(int step = 1; i + step < n; step++)
            {
                StringBuilder sb = new StringBuilder();
                sb.append(str.charAt(i));
                int cur = i + step;
                while(cur < n)
                {
                    sb.append(str.charAt(cur));
                    // System.out.println(sb);
                    map.put(sb.toString(), map.getOrDefault(sb.toString(), 0) + 1);
                    maxi = Math.max(maxi, map.get(sb.toString()));
                    cur += step;
                }
            }
            // map.get(c).add(i);
        }

        out.println(maxi);
        // out.println(map);

        /****************************************************/
        /****************************************************/
        /****************************************************/
        /****************************************************/

        out.flush();
    }
}


#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <tuple>

using namespace std;

bool check(char& letter, int& iVal, int& jVal)
{
  bool flag = false;
  if ((letter == '>' && iVal > jVal)
   || (letter == '<' && iVal < jVal)
   || (letter == '=' && iVal == jVal))
    flag = true;

  return flag;
}

int rightJVal(char& letter, int& iVal)
{
  int jVal = 0;
  if (letter == '>')
    jVal = iVal - 1;
  else if (letter == '<')
    jVal = iVal + 1;
  else
    jVal = iVal;

  return jVal;
}

int rightIVal(char& letter, int& jVal)
{
  int iVal = 0;
  if (letter == '>')
    iVal = jVal + 1;
  else if (letter == '<')
    iVal = jVal - 1;
  else
    iVal = jVal;

  return iVal;
}

int main()
{
  int n, m;
  vector<string> data;
  vector< vector<int> > set;
  bool yes;
  vector< tuple<int, int> > open;
  map< tuple<int, int>, bool > closed;

  cin >> n >> m;
  set.resize(2);
  set[0].resize(n, 0);
  set[1].resize(m, 0);

  for (int i = 0; i < n; ++i)
  {
    string row;
    cin >> row;
    data.push_back(row);
  }

  auto root = make_tuple(0, 0);
  open.push_back(root);

  while (open.size() > 0)
  {
    auto node = open.back();
    open.pop_back();
    closed[node] = true;
    if (get<0>(node) == 0)
    {
      int i = get<1>(node);
      for (int j = 0; j < m; ++j)
      {
        if (closed.count(make_tuple(1, j)) == 0
          && !check(data[i][j], set[0][i], set[1][j]))
        {
          set[1][j] = rightJVal(data[i][j], set[0][i]);
          open.push_back(make_tuple(1, j));
        }
      }
    }
    else
    {
      int j = get<1>(node);
      for (int i = 0; i < n; ++i)
      {
        if (closed.count(make_tuple(0, i)) == 0
         && !check(data[i][j], set[0][i], set[1][j]))
        {
          set[0][i] = rightIVal(data[i][j], set[1][j]);
          open.push_back(make_tuple(0, i));
        }
      }
    }
  }

  yes = true;
  for (int i = 0; i < n && yes; ++i)
  {
    for (int j = 0; j < m && yes; ++j)
    {
      if (!check(data[i][j], set[0][i], set[1][j]))
        yes = false;
    }
  }

  if (yes)
  {
    cout << "Yes" << endl;
    int min = set[0][0];
    for (auto num: set[0])
        if (min > num)
            min = num;
    for (auto num: set[1])
        if (min > num)
            min = num;
    int offset = 1 - min;
    for (int i = 0; i < n; ++i)
        cout << (set[0][i] + offset) << ' ';
    cout << endl;
    for (int j = 0; j < m; ++j)
        cout << (set[1][j] + offset) << ' ';
    cout << endl;
  }
  else
  {
    cout << "No" << endl;
  }

  return 0;
}


#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <tuple>

using namespace std;

int main()
{
  int n, m;
  vector<string> data;
  vector< vector<int> > set;
  bool yes;
  vector< tuple<int, int> > open;
  map< tuple<int, int>, bool > closed;

  cin >> n >> m;
  set.resize(2);
  set[0].resize(n, 0);
  set[1].resize(m, 0);

  for (int i = 0; i < n; ++i)
  {
    string row;
    cin >> row;
    data.push_back(row);
  }

  for (int i = 0; i < n; ++i)
  {
    int count = 0;
    for (int j = 0; j < m; ++j)
    {
      if (data[i][j] == '>')
        count++;
    }
    if (count > 0)
      continue;

    open.push_back(make_tuple(0, i));
    while (open.size() > 0)
    {
      auto node = open.back();
      open.pop_back();
      closed[node] = true;
      if (get<0>(node) == 0)
      {
        int i = get<1>(node);
        for (int j = 0; j < m; ++j)
        {
          if (closed.count(make_tuple(1, j)) > 0)
            continue;
          if (data[i][j] == '<' && set[0][i] >= set[1][j])
          {
            set[1][j] = set[0][i] + 1;
            open.push_back(make_tuple(1, j));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[1][j] = set[0][i];
            open.push_back(make_tuple(1, j));
          }
        }
      }
      else
      {
        int j = get<1>(node);
        for (int i = 0; i < n; ++i)
        {
          if (closed.count(make_tuple(0, i)) > 0)
            continue;
          if (data[i][j] == '>' && set[0][i] <= set[1][j])
          {
            set[0][i] = set[1][j] + 1;
            open.push_back(make_tuple(0, i));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[0][i] = set[1][j];
            open.push_back(make_tuple(0, i));
          }
        }
      }
    }
    open.clear();
    closed.clear();
  }

  for (int i = 0; i < n; ++i)
  {
    int count = 0;
    for (int j = 0; j < m; ++j)
    {
      if (data[i][j] == '<')
        count++;
    }
    if (count > 0)
      continue;

    open.push_back(make_tuple(0, i));
    while (open.size() > 0)
    {
      auto node = open.back();
      open.pop_back();
      closed[node] = true;
      if (get<0>(node) == 0)
      {
        int i = get<1>(node);
        for (int j = 0; j < m; ++j)
        {
          if (closed.count(make_tuple(1, j)) > 0)
            continue;
          if (data[i][j] == '>' && set[0][i] <= set[1][j])
          {
            set[1][j] = set[0][i] - 1;
            open.push_back(make_tuple(1, j));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[1][j] = set[0][i];
            open.push_back(make_tuple(1, j));
          }
        }
      }
      else
      {
        int j = get<1>(node);
        for (int i = 0; i < n; ++i)
        {
          if (closed.count(make_tuple(0, i)) > 0)
            continue;
          if (data[i][j] == '<' && set[0][i] >= set[1][j])
          {
            set[0][i] = set[1][j] - 1;
            open.push_back(make_tuple(0, i));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[0][i] = set[1][j];
            open.push_back(make_tuple(0, i));
          }
        }
      }
    }
    open.clear();
    closed.clear();
  }

  for (int j = 0; j < m; ++j)
  {
    int count = 0;
    for (int i = 0; i < n; ++i)
    {
      if (data[i][j] == '<')
        count++;
    }
    if (count > 0)
      continue;

    open.push_back(make_tuple(1, j));
    while (open.size() > 0)
    {
      auto node = open.back();
      open.pop_back();
      closed[node] = true;
      if (get<0>(node) == 0)
      {
        int i = get<1>(node);
        for (int j = 0; j < m; ++j)
        {
          if (closed.count(make_tuple(1, j)) > 0)
            continue;
          if (data[i][j] == '<' && set[0][i] >= set[1][j])
          {
            set[1][j] = set[0][i] + 1;
            open.push_back(make_tuple(1, j));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[1][j] = set[0][i];
            open.push_back(make_tuple(1, j));
          }
        }
      }
      else
      {
        int j = get<1>(node);
        for (int i = 0; i < n; ++i)
        {
          if (closed.count(make_tuple(0, i)) > 0)
            continue;
          if (data[i][j] == '>' && set[0][i] <= set[1][j])
          {
            set[0][i] = set[1][j] + 1;
            open.push_back(make_tuple(0, i));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[0][i] = set[1][j];
            open.push_back(make_tuple(0, i));
          }
        }
      }
    }
    open.clear();
    closed.clear();
  }

  for (int j = 0; j < m; ++j)
  {
    int count = 0;
    for (int i = 0; i < n; ++i)
    {
      if (data[i][j] == '>')
        count++;
    }
    if (count > 0)
      continue;

    open.push_back(make_tuple(1, j));
    while (open.size() > 0)
    {
      auto node = open.back();
      open.pop_back();
      closed[node] = true;
      if (get<0>(node) == 0)
      {
        int i = get<1>(node);
        for (int j = 0; j < m; ++j)
        {
          if (closed.count(make_tuple(1, j)) > 0)
            continue;
          if (data[i][j] == '>' && set[0][i] <= set[1][j])
          {
            set[1][j] = set[0][i] - 1;
            open.push_back(make_tuple(1, j));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[1][j] = set[0][i];
            open.push_back(make_tuple(1, j));
          }
        }
      }
      else
      {
        int j = get<1>(node);
        for (int i = 0; i < n; ++i)
        {
          if (closed.count(make_tuple(0, i)) > 0)
            continue;
          if (data[i][j] == '<' && set[0][i] >= set[1][j])
          {
            set[0][i] = set[1][j] - 1;
            open.push_back(make_tuple(0, i));
          }
          else if (data[i][j] == '=' && set[0][i] != set[1][j])
          {
            set[0][i] = set[1][j];
            open.push_back(make_tuple(0, i));
          }
        }
      }
    }
    open.clear();
    closed.clear();
  }

  yes = true;
  for (int i = 0; i < n && yes; ++i)
  {
    for (int j = 0; j < m && yes; ++j)
    {
      if ((data[i][j] == '<' && set[0][i] >= set[1][j])
       || (data[i][j] == '>' && set[0][i] <= set[1][j])
       || (data[i][j] == '=' && set[0][i] != set[1][j]))
        yes = false;
    }
  }

  if (yes)
  {
    cout << "Yes" << endl;
    int min = set[0][0];
    for (auto num: set[0])
        if (min > num)
            min = num;
    for (auto num: set[1])
        if (min > num)
            min = num;
    int offset = 1 - min;
    for (int i = 0; i < n; ++i)
        cout << (set[0][i] + offset) << ' ';
    cout << endl;
    for (int j = 0; j < m; ++j)
        cout << (set[1][j] + offset) << ' ';
    cout << endl;
  }
  else
  {
    cout << "No" << endl;
  }

  return 0;
}


#include <iostream>
#include <map>
#include <vector>

using namespace std;

int main()
{
  int n, m;
  vector<string> data;

  cin >> n >> m;
  for (int i = 0; i < n; ++i)
  {
    string row;
    cin >> row;
    data.push_back(row);
  }

  vector< vector<int> > set;
  set.resize(2);
  set[0].resize(n, 0);
  set[1].resize(m, 0);

  vector< vector<int> > setJcan;
  setJcan.resize(n);
  for (auto& v: setJcan)
    v.resize(m);
  for (int i = 0; i < n; ++i)
  {
    for (int j = 0; j < m; ++j)
    {
      if (data[i][j] == '>')
        setJcan[i][j] = -1;
      if (data[i][j] == '<')
        setJcan[i][j] = 1;
      if (data[i][j] == '=')
        setJcan[i][j] = 0;
    }
    int min = 0;
    for (int j = 0; j < m; ++j)
      if (min > setJcan[i][j])
        min = setJcan[i][j];
    set[0][i] = set[0][i] + (1 - min);
    for (int j = 0; j < m; ++j)
    {
      setJcan[i][j] = setJcan[i][j] + (1 - min);
    }
  }

  map<int, bool> done;
  int count = 0;
  while(done.size() < (unsigned int)m && count < n * m)
  {
    // find min of max in column
    int min = -1;
    int j_min;
    for (int j = 0; j < m; ++j)
    {
      if (done.count(j) > 0)
        continue;
      int minmin = -1;
      for (int i = 0; i < n; ++i)
      {
        if (minmin == -1 || minmin > setJcan[i][j])
          minmin = setJcan[i][j];
      }
      if (min == -1 || min > minmin)
      {
        min = minmin;
        j_min = j;
      }
    }
    // fix
    int max = 0;
    for (int i = 0; i < n; ++i)
    {
      if (max < setJcan[i][j_min])
      {
        max = setJcan[i][j_min];
      }
    }
    bool updated = false;
    for (int i = 0; i < n; ++i)
    {
      int diff = max - setJcan[i][j_min];
      if (diff == 0)
        continue;
      if (set[0][i] >= setJcan[i][j_min] && set[0][i] <= max)
      {
        int newSetI;
        if (set[0][i] == setJcan[i][j_min])
          newSetI = max;
        else
          newSetI = max + 1;
        for (int j = 0; j < m; ++j)
        {
          if (j == j_min)
            continue;
          if (setJcan[i][j] >= set[0][i] && setJcan[i][j] <= newSetI)
          {
            if (setJcan[i][j] == set[0][i])
              setJcan[i][j] = newSetI;
            else
              setJcan[i][j] = newSetI + 1;
          }
        }
        set[0][i] = newSetI;
      }
      setJcan[i][j_min] += diff;
      updated = true;
    }
    if (!updated)
      done[j_min] = true;

    count++;
  }

  for (int j = 0; j < m; ++j)
  {
    set[1][j] = setJcan[0][j];
  }

  bool yes = true;

  for (int i = 0; i < n && yes; ++i)
  {
    for (int j = 0; j < m && yes; ++j)
    {
      if (data[i][j] == '>' && set[0][i] <= set[1][j])
        yes = false;
      if (data[i][j] == '=' && set[0][i] != set[1][j])
        yes = false;
      if (data[i][j] == '<' && set[0][i] >= set[1][j])
        yes = false;
    }
  }

  if (yes)
  {
    cout << "Yes" << endl;
    int min = set[0][0];
    for (auto num: set[0])
        if (min > num)
            min = num;
    for (auto num: set[1])
        if (min > num)
            min = num;
    int offset = 1 - min;
    for (int i = 0; i < n; ++i)
        cout << (set[0][i] + offset) << ' ';
    cout << endl;
    for (int j = 0; j < m; ++j)
        cout << (set[1][j] + offset) << ' ';
    cout << endl;
  }
  else
  {
    cout << "No" << endl;

    // cout << "i: ";
    // for (auto i : set[0])
    //   cout << i << ", ";
    // cout << endl;
    // cout << "j: ";
    // for (auto j : set[1])
    //   cout << j << ", ";
    // cout << endl;
  }

  return 0;
}


#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <tuple>

using namespace std;

bool check(char& letter, int& iVal, int& jVal)
{
  bool flag = false;
  if ((letter == '>' && iVal > jVal)
   || (letter == '<' && iVal < jVal)
   || (letter == '=' && iVal == jVal))
    flag = true;

  return flag;
}

int rightJVal(char& letter, int& iVal)
{
  int jVal = 0;
  if (letter == '>')
    jVal = iVal - 1;
  else if (letter == '<')
    jVal = iVal + 1;
  else
    jVal = iVal;

  return jVal;
}

int rightIVal(char& letter, int& jVal)
{
  int iVal = 0;
  if (letter == '>')
    iVal = jVal + 1;
  else if (letter == '<')
    iVal = jVal - 1;
  else
    iVal = jVal;

  return iVal;
}

int main()
{
  int n, m;
  vector<string> data;
  vector< vector<int> > set;
  bool yes;
  vector< tuple<int, int> > open;
  map< tuple<int, int>, bool > closed;

  cin >> n >> m;
  set.resize(2);
  set[0].resize(n, 0);
  set[1].resize(m, 0);

  for (int i = 0; i < n; ++i)
  {
    string row;
    cin >> row;
    data.push_back(row);
  }

  vector< tuple<int, int> > roots;
  for (int i = 0; i < n; ++i)
  {
    int countG = 0;
    int countL = 0;
    for (int j = 0; j < m; ++j)
    {
      if (data[i][j] == '<')
        ++countL;
      if (data[i][j] == '>')
        ++countG;
    }
    if (countG == 0 || countL == 0)
      roots.push_back(make_tuple(0,i));
  }
  for (int j = 0; j < m; ++j)
  {
    int countG = 0;
    int countL = 0;
    for (int i = 0; i < n; ++i)
    {
      if (data[i][j] == '<')
        ++countL;
      if (data[i][j] == '>')
        ++countG;
    }
    if (countG == 0 || countL == 0)
      roots.push_back(make_tuple(1,j));
  }
  if (roots.size() == 0)
    roots.push_back(make_tuple(0, 0));

  for (auto root: roots)
  {
    open.push_back(root);

    while (open.size() > 0)
    {
      auto node = open.back();
      open.pop_back();
      closed[node] = true;
      if (get<0>(node) == 0)
      {
        int i = get<1>(node);
        for (int j = 0; j < m; ++j)
        {
          if (closed.count(make_tuple(1, j)) == 0
            && !check(data[i][j], set[0][i], set[1][j]))
          {
            set[1][j] = rightJVal(data[i][j], set[0][i]);
            open.push_back(make_tuple(1, j));
          }
        }
      }
      else
      {
        int j = get<1>(node);
        for (int i = 0; i < n; ++i)
        {
          if (closed.count(make_tuple(0, i)) == 0
           && !check(data[i][j], set[0][i], set[1][j]))
          {
            set[0][i] = rightIVal(data[i][j], set[1][j]);
            open.push_back(make_tuple(0, i));
          }
        }
      }
    }
    open.clear();
    closed.clear();
  }

  yes = true;
  for (int i = 0; i < n && yes; ++i)
  {
    for (int j = 0; j < m && yes; ++j)
    {
      if (!check(data[i][j], set[0][i], set[1][j]))
        yes = false;
    }
  }

  if (yes)
  {
    cout << "Yes" << endl;
    int min = set[0][0];
    for (auto num: set[0])
        if (min > num)
            min = num;
    for (auto num: set[1])
        if (min > num)
            min = num;
    int offset = 1 - min;
    for (int i = 0; i < n; ++i)
        cout << (set[0][i] + offset) << ' ';
    cout << endl;
    for (int j = 0; j < m; ++j)
        cout << (set[1][j] + offset) << ' ';
    cout << endl;
  }
  else
  {
    cout << "No" << endl;
  }

  return 0;
}


#include <iostream>
#include <map>
#include <vector>

using namespace std;

int main()
{
  int n, m;
  vector<string> data;

  cin >> n >> m;
  for (int i = 0; i < n; ++i)
  {
    string row;
    cin >> row;
    data.push_back(row);
  }

  vector< vector<int> > set;
  set.resize(2);
  set[0].resize(n, 0);
  set[1].resize(m, 0);

  vector< vector<int> > setJcan;
  setJcan.resize(n);
  for (auto& v: setJcan)
    v.resize(m);
  for (int i = 0; i < n; ++i)
  {
    for (int j = 0; j < m; ++j)
    {
      if (data[i][j] == '>')
        setJcan[i][j] = -1;
      if (data[i][j] == '<')
        setJcan[i][j] = 1;
      if (data[i][j] == '=')
        setJcan[i][j] = 0;
    }
    int min = 0;
    for (int j = 0; j < m; ++j)
      if (min > setJcan[i][j])
        min = setJcan[i][j];
    set[0][i] = set[0][i] + (1 - min);
    for (int j = 0; j < m; ++j)
    {
      setJcan[i][j] = setJcan[i][j] + (1 - min);
    }
  }

  map<int, bool> done;
  vector<int> minJ(m);
  for (int j = 0; j < m; ++j)
  {
    minJ[j] = -1;
    for (int i = 0; i < n; ++i)
    {
      if (minJ[j] == -1 || minJ[j] > setJcan[i][j])
        minJ[j] = setJcan[i][j];
    }
  }

  int consecutive_update_count = 0;
  while(done.size() < (unsigned int)m && consecutive_update_count <= 2*m)
  {
    // find min of max in column
    int min = -1;
    int j_min;
    for (int j = 0; j < m; ++j)
    {
      if (done.count(j) > 0)
        continue;
      if (min == -1 || min > minJ[j])
      {
        min = minJ[j];
        j_min = j;
      }
    }
    // fix
    int max = 0;
    for (int i = 0; i < n; ++i)
    {
      if (max < setJcan[i][j_min])
      {
        max = setJcan[i][j_min];
      }
    }
    minJ[j_min] = max;
    bool updated = false;
    for (int i = 0; i < n; ++i)
    {
      int diff = max - setJcan[i][j_min];
      if (diff == 0)
        continue;
      if (set[0][i] >= setJcan[i][j_min] && set[0][i] <= max)
      {
        int newSetI;
        if (set[0][i] == setJcan[i][j_min])
          newSetI = max;
        else
          newSetI = max + 1;
        for (int j = 0; j < m; ++j)
        {
          if (j == j_min)
            continue;
          if (setJcan[i][j] >= set[0][i] && setJcan[i][j] <= newSetI)
          {
            if (setJcan[i][j] == set[0][i])
              setJcan[i][j] = newSetI;
            else
              setJcan[i][j] = newSetI + 1;
          }
        }
        set[0][i] = newSetI;
      }
      setJcan[i][j_min] += diff;
      updated = true;
    }
    if (updated)
    {
      consecutive_update_count++;
    }
    else
    {
      done[j_min] = true;
      consecutive_update_count = 0;
    }
  }

  for (int j = 0; j < m; ++j)
  {
    set[1][j] = setJcan[0][j];
  }

  bool yes = true;

  for (int i = 0; i < n && yes; ++i)
  {
    for (int j = 0; j < m && yes; ++j)
    {
      if (data[i][j] == '>' && set[0][i] <= set[1][j])
        yes = false;
      if (data[i][j] == '=' && set[0][i] != set[1][j])
        yes = false;
      if (data[i][j] == '<' && set[0][i] >= set[1][j])
        yes = false;
    }
  }

  if (yes)
  {
    cout << "Yes" << endl;
    int min = set[0][0];
    for (auto num: set[0])
        if (min > num)
            min = num;
    for (auto num: set[1])
        if (min > num)
            min = num;
    int offset = 1 - min;
    for (int i = 0; i < n; ++i)
        cout << (set[0][i] + offset) << ' ';
    cout << endl;
    for (int j = 0; j < m; ++j)
        cout << (set[1][j] + offset) << ' ';
    cout << endl;
  }
  else
  {
    cout << "No" << endl;

    // cout << "i: ";
    // for (auto i : set[0])
    //   cout << i << ", ";
    // cout << endl;
    // cout << "j: ";
    // for (auto j : set[1])
    //   cout << j << ", ";
    // cout << endl;
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=20000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+n)) ok=0;

    if(!ok) return printf("No"),0;

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[j+n].push_back(i),in[i]++;
        else if(mp[i][j]=='<') edge[i].push_back(j+n),in[j+n]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;
    int cnt=0;
    while(!q.empty()) {
        auto u=q.front();q.pop();cnt++;
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        ans[find1(u.x)]=max(ans[find1(u.x)],temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    //cout<<cnt<<endl;
    if(cnt!=n+m) return printf("No"),0;
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",ans[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",ans[find1(i+n)]);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+m)) ok=0;
    if(!ok) return printf("No"),0;

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[j+n].push_back(i),in[i]++;
        else if(mp[i][j]=='<') edge[i].push_back(j+n),in[j+n]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;
    int cnt=0;
    while(!q.empty()) {
        auto u=q.front();q.pop();cnt++;
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        ans[find1(u.x)]=max(ans[find1(u.x)],temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    if(cnt!=n+m) return printf("No"),0;
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",ans[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",ans[find1(i+n)]);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x,d;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;

    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+m)) ok=0;
    if(!ok) return printf("No"),0;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[j+n].push_back(i),in[i]++;
        else if(mp[i][j]=='<') edge[i].push_back(j+n),in[j+n]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;

    while(!q.empty()) {
        auto u=q.front();q.pop();
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        ans[find1(u.x)]=max(ans[find1(u.x)],temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",ans[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",ans[find1(i+n)]);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+n)) ok=0;

    if(!ok) return printf("No"),0;

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[j+n].push_back(i),in[i]++;
        else if(mp[i][j]=='<') edge[i].push_back(j+n),in[j+n]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;
    int cnt=0;
    while(!q.empty()) {
        auto u=q.front();q.pop();cnt++;
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        ans[find1(u.x)]=max(ans[find1(u.x)],temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    //cout<<cnt<<endl;
    if(cnt!=n+m) return printf("No"),0;
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",ans[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",ans[find1(i+n)]);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+n)) ok=0;

    //if(!ok) return printf("No"),0;

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[j+n].push_back(i),in[i]++;
        else if(mp[i][j]=='<') edge[i].push_back(j+n),in[j+n]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;
    int cnt=0;
    while(!q.empty()) {
        auto u=q.front();q.pop();cnt++;
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        ans[find1(u.x)]=max(ans[find1(u.x)],temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    //cout<<cnt<<endl;
    if(cnt!=n+m) return printf("No"),0;
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",ans[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",ans[find1(i+n)]);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+n)) ok=0;

    if(!ok) return printf("No"),0;

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[j+n].push_back(i),in[i]++;
        else if(mp[i][j]=='<') edge[i].push_back(j+n),in[j+n]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;
    int cnt=0;
    while(!q.empty()) {
        auto u=q.front();q.pop();cnt++;
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        ans[find1(u.x)]=max(ans[find1(u.x)],temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    //cout<<cnt<<endl;
    if(cnt!=n+m) return printf("No"),0;
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",ans[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",ans[find1(i+n)]);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5000+100;
const ll mod=1e9+7;

int f[N],L[N],R[N],aL[N],aR[N];
int find1(int x) {
    return f[x]==x?x:f[x]=find1(f[x]);
}
void union1(int x,int y) {
    x=find1(x);y=find1(y);
    if(x!=y) f[x]=y;
}
int ans[N+N],in[N+N],temp[N];
char mp[N][N];
vector<int>edge[N+N];
struct node {
    int x;
};
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i,temp[i]=1;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]=='=')
            union1(i,j+n);
    int ok=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(mp[i][j]!='=')
            if(find1(i)==find1(j+n)) ok=0;

    if(!ok) return printf("No"),0;

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        if(mp[i][j]=='>') edge[find1(j+n)].push_back(find1(i)),in[find1(i)]++;
        else if(mp[i][j]=='<') edge[find1(i)].push_back(find1(j+n)),in[find1(j+n)]++;
    }
    queue<node>q;
    for(int i=1;i<=n+m;i++) if(!in[i]) q.push({i}),temp[i]=1;
    int cnt=0;
    while(!q.empty()) {
        auto u=q.front();q.pop();cnt++;
        //printf("u=%d temp=%d\n",u.x,temp[u.x]);
        for(auto v:edge[u.x]) {
            temp[v]=max(temp[v],temp[u.x]+1);
            if(--in[v]==0) q.push({v});
        }
    }
    //cout<<cnt<<endl;
    if(cnt!=n+m) return printf("No"),0;
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++) printf("%d ",temp[find1(i)]);cout<<endl;
    for(int i=1;i<=m;i++) printf("%d ",temp[find1(i+n)]);
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 100030;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] > N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    if(Dist[N] == 0)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0),AddEdges(j+N,i,0);
        }

    SPFA(1,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 200030;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = -INF;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(0,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 100030;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = 0;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp >= Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0),AddEdges(j+N,i,0);
        }

    SPFA(1,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1000300;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = 0;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(0,N + M , N);

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1005300;

int Dist[MAXN],vis[MAXN],outque[MAXN];

vector< pair<int,int> > edge[MAXN];

void AddEdges(int u,int v,int w)
{
    edge[u].push_back( make_pair(v,w) );
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(Dist,0,sizeof Dist);
    Dist[s] = 0;
    vis[s] = 1;
    deque<int> Q;
    for (int s = 1 ; s <=N ; s++)
        Q.push_back(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop_front();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1)
        {
            ans = -1;
            break;
        }
        for (int i = 0 ; i < edge[u].size(); i++)
        {
            pair<int,int> c = edge[u][i];
            int v = c.first;
            int w = c.second;
            if (Dist[u] + w > Dist[v])
            {
                Dist[v] = Dist[u] + w;
                if (!vis[v])
                {
                    vis[v] = 1;
                    if (Q.empty() || Dist[v] > Dist[Q.front()]) Q.push_back(v);
                    else Q.push_front(v);
                }
            }
        }
    }
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);
    //for (int i = 1 ; i <= N + M ; i++)
    //    AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }
    SPFA(0,N + M , N);
    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1000300;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = -INF;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(0,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1000300;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));

    Dist[s] = 0;
    vis[s] = 1;
    deque<int> Q;
    Q.push_back(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop_front();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1)
        {
            ans = -1;
            break;
        }
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            int v=Edges[i].to;
            if(temp > Dist[v])
            {
                Dist[v] = temp;
                if( !vis[v])
                {
                    vis[v] = 1;
                    //Q.push(Edges[i].to);
                    if (Q.empty() || Dist[v] > Dist[Q.front()]) Q.push_back(v);
                    else Q.push_front(v);
                }
            }
        }
    }
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }
    SPFA(0,N + M , N);
    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 100030;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = -1;
    Dist[s] = -1;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp >= Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(1,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1005300;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));

    Dist[s] = 0;
    vis[s] = 1;
    deque<int> Q;
    Q.push_back(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop_front();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1)
        {
            ans = -1;
            break;
        }
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            int v=Edges[i].to;
            if(temp > Dist[v])
            {
                Dist[v] = temp;
                if( !vis[v])
                {
                    vis[v] = 1;
                    //Q.push(Edges[i].to);
                    if (Q.empty() || Dist[v] > Dist[Q.front()]) Q.push_back(v);
                    else Q.push_front(v);
                }
            }
        }
    }
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }
    SPFA(0,N + M , N);
    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1005300;

int Dist[MAXN],vis[MAXN],outque[MAXN];

vector< pair<int,int> > edge[MAXN];

void AddEdges(int u,int v,int w)
{
    edge[u].push_back( make_pair(v,w) );
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    Dist[s] = 0;
    vis[s] = 1;
    deque<int> Q;
    Q.push_back(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop_front();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1)
        {
            ans = -1;
            break;
        }
        for (int i = 0 ; i < edge[u].size(); i++)
        {
            pair<int,int> c = edge[u][i];
            int v = c.first;
            int w = c.second;
            if (Dist[u] + w > Dist[v])
            {
                Dist[v] = Dist[u] + w;
                if (!vis[v])
                {
                    vis[v] = 1;
                    if (Q.empty() || Dist[v] > Dist[Q.front()]) Q.push_back(v);
                    else Q.push_front(v);
                }
            }
        }
    }
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);
    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }
    SPFA(0,N + M , N);
    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 1000300;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = 0;
    Dist[s] = 0;
    vis[s] = 1;
    deque<int> Q;
    Q.push_back(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop_front();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    //Q.push(Edges[i].to);
                    if (Q.empty() || Dist[Edges[i].to] > Dist[Q.front()]) Q.push_back(Dist[Edges[i].to]);
                    else Q.push_front(Dist[Edges[i].to]);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(0,N + M , N);

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 100030;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = -INF;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            if (Dist[i] < 0)
            printf("%d ",Dist[0] + mx);
            else
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            if (Dist[i] < 0)
            printf("%d ",Dist[0] + mx);
        else
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(1,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2100;
const int MAXM = 100030;

struct EdgeNode
{
    int to;
    int w;
    int next;
} Edges[MAXM];

int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N,int wsnb)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = -INF;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] >= N+1) //如果出队次数大于N，则说明出现负环
        {
            ans = -1;
            break;
        }

        //cout << u << endl;
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp > Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }

    //for (int i = 1 ; i <= N ; i++) cout << Dist[i] << endl;
    if(ans == -1)
        printf("No\n");
    else
    {
        int mx = 0;
        for (int i = 1 ; i <= N ; i++) mx = max(mx,Dist[i]);
        mx++;
        printf("Yes\n");
        for (int i = 1 ; i <= wsnb ; i++)
            printf("%d ",-Dist[i] + mx);
        printf("\n");
        for (int i = wsnb+1 ; i <=N ; i++)
            printf("%d ",-Dist[i] + mx);
    }
}

char s[1050][1050];

int main()
{
    int N,M,u,v,w;
    cin >> N >> M;
    memset(Head,-1,sizeof(Head));

    for (int i = 1 ; i <= N ; i++)
        scanf("%s",s[i]+1);

    for (int i = 1 ; i <= N + M ; i++)
        AddEdges(0,i,1);
    for (int i = 1 ; i <= N ; i++)
        for (int j = 1 ;  j <= M ; j++)
        {
            if (s[i][j] == '>') AddEdges(i , j + N , 1);
            if (s[i][j] == '<') AddEdges(j+ N, i ,1);
            if (s[i][j] == '=') AddEdges(i,j+N,0) , AddEdges(j+N,i,0);
        }

    SPFA(0,N + M , N);  //求使得源点 s 到 终点 t 的最大的值

    return 0;
}


//
//  main.cpp
//  GourmetChoice
//
//  Created by Cynthia Du on 3/21/20.
//  Copyright © 2020 Cynthia Du. All rights reserved.
//

#include <bits/stdc++.h>
#include <iostream>
using namespace std;
int n, m;
int resN[1005], resM[1005];
char c;

int main(int argc, const char * argv[]) {
    cin >> n >> m;
    vector<set<int>> s (n);
    vector<set<int>> e (n);

    for (int i = 0; i < n; i++) for (int j = 0; j < m; j++){
        cin >>c;
        if (c-'>'== 0) s[i].insert(j);
        if (c-'=' == 0) e[i].insert(j);
    }
    vector<pair<int, int>> process;
    for (int i = 0; i < n; i++){
        process.push_back(make_pair(s[i].size(), i));
    }
    int counter = 0;
    sort(process.begin(), process.end());
    set<int> allAssigned;
    int idx = 0;
    while (idx < process.size()){
        int mainDish = process[idx].second;
        int right = idx;
        while (right < process.size() && process[right].first == process[idx].first) right++;

        //Check
        set<int> mS = s[mainDish]; set<int> mE = e[mainDish];
        if (!includes(mS.begin(), mS.end(), allAssigned.begin(), allAssigned.end())) {cout<<"NO"<<endl; return 0;}

        for (int j = idx+1; j < right; j++){
            int jDish = process[j].second;
            set<int> jS = s[jDish]; set<int> jE = e[jDish];
            if (mS != jS || mE != jE) {cout<<"NO"<<endl; return 0;}
        }

        int amtInBetween = mS.size()-allAssigned.size()> 0;
        //Assign
        counter++;
        for (auto d : mS){
            if (resM[d] == 0) resM[d] = counter;
            allAssigned.insert(d);
        }

        if (amtInBetween> 0) counter++;
        for (auto d : mE) {
            if (resM[d] == 0) resM[d] = counter;
            allAssigned.insert(d);
        }
        for (int j = idx; j < right; j++) resN[process[j].second] = counter;

        idx = right;
    }
    cout<<resN[0];
    for (int i = 1; i < n; i++) cout<<" "<<resN[i];
    cout<<endl;
    cout<<resM[0];
    for (int i = 1; i < m; i++) cout<<" "<<resM[i];
    cout<<endl;

    return 0;
}

//Notes:
//1. Used vector instead of set; so had to laboriously check, code was awful