You are given two strings A and B representing essays of two students who are suspected cheaters. For any two strings C, D we define their similarity score S(C,D) as 4⋅ LCS(C,D) - |C| - |D|, where LCS(C,D) denotes the length of the Longest Common Subsequence of strings C and D. 

You believe that only some part of the essays could have been copied, therefore you're interested in their substrings.

Calculate the maximal similarity score over all pairs of substrings. More formally, output maximal S(C, D) over all pairs (C, D), where C is some substring of A, and D is some substring of B. 

If X is a string, |X| denotes its length.

A string a is a substring of a string b if a can be obtained from b by deletion of several (possibly, zero or all) characters from the beginning and several (possibly, zero or all) characters from the end.

A string a is a subsequence of a string b if a can be obtained from b by deletion of several (possibly, zero or all) characters. 

Pay attention to the difference between the substring and subsequence, as they both appear in the problem statement. 

You may wish to read the [Wikipedia page about the Longest Common Subsequence problem](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem).

Input

The first line contains two positive integers n and m (1 ≤ n, m ≤ 5000) — lengths of the two strings A and B. 

The second line contains a string consisting of n lowercase Latin letters — string A.

The third line contains a string consisting of m lowercase Latin letters — string B. 

Output

Output maximal S(C, D) over all pairs (C, D), where C is some substring of A, and D is some substring of B. 

Examples

Input


4 5
abba
babab


Output


5

Input


8 10
bbbbabab
bbbabaaaaa


Output


12

Input


7 7
uiibwws
qhtkxcn


Output


0

Note

For the first case:

abb from the first string and abab from the second string have LCS equal to abb.

The result is S(abb, abab) = (4 ⋅ |abb|) - |abb| - |abab| = 4 ⋅ 3 - 3 - 4 = 5.
#include <bits/stdc++.h>
using namespace std;
using unsigned_int = unsigned int;
using need_int = int;
using counter_type = int;
using MAIN = int;
using ll = long long;
template <typename T>
using PairOf = pair<T, T>;
using Void = tuple<>;
namespace mytl {
template <typename T, typename R, typename F = function<R(T)>>
vector<R> fmap(F f, const vector<T>& t) {
  vector<R> res;
  for (auto elem : t) res.push_back(f(elem));
  return res;
}
template <typename T>
vector<T> forrange(T n, T from) {
  vector<T> res(n);
  iota(res.begin(), res.end(), from);
  return res;
}
template <typename F>
void repeat(need_int n, const F& callback) {
  for (need_int _ : forrange(n, 0)) callback();
}
}  // namespace mytl
namespace mytl {
template <typename T, typename Pred>
T discrete_binary_search(T l, T r, Pred f) {
  assert(f(l));
  while (l < r) {
    T pivot = (l + r + 1) / 2;
    if (!f(pivot))
      r = pivot - 1;
    else
      l = pivot;
  }
  return l;
}
template <typename T, typename Pred>
T continuous_binary_search(T l, T r, need_int iterations, Pred f) {
  mytl::repeat(iterations, [&]() {
    T pivot = (l + r) / 2;
    if (f(pivot))
      l = pivot;
    else
      r = pivot;
  });
  return l;
}
}  // namespace mytl
namespace mytl {
template <typename T>
struct LazyVector : vector<T> {
  inline typename vector<T>::reference operator[](need_int i) {
    if (i >= vector<T>::size()) vector<T>::resize(i + 1);
    return vector<T>::operator[](i);
  }
};
template <typename T>
struct TwoWayLazyVector {
  LazyVector<T> negative, positive;
  inline typename vector<T>::reference operator[](need_int i) {
    if (i >= 0) {
      return positive[i];
    } else {
      return negative[-i];
    }
  }
};
template <typename T>
struct optional {
  T* ptr = nullptr;
  inline void set(const T& val) { ptr = new T(val); }
  inline optional() {}
  inline optional(const T& val) { set(val); }
  optional& operator=(const T& val) {
    set(val);
    return *this;
  }
  ~optional() { delete ptr; }
  inline T value() const { return *ptr; }
  inline bool has_value() const { return ptr != nullptr; }
  optional& operator=(const optional& other) {
    if (other.has_value()) {
      set(other.value());
    } else {
      ptr = nullptr;
    }
    return *this;
  }
  optional(const optional& other) { operator=(other); }
  optional(optional&& other) {
    ptr = other.ptr;
    other.ptr = nullptr;
  }
  optional& operator=(optional&& other) {
    if (this != &other) {
      delete ptr;
      ptr = other.ptr;
      other.ptr = nullptr;
      return *this;
    }
  }
};
}  // namespace mytl
namespace mytl {
template <typename Op_>
struct Trie {
  struct Node;
  using Op = Op_;
  using T = typename Op::T;
  using Info = typename Op::template Info<Node>;
  using Next_Container = typename Op::template Next<Node*>;
  struct Node : Info {
    Node* parent;
    T last;
    Next_Container next;
    need_int leaf = 0;
    Node* jump(T c) {
      if (next.contains(c)) {
        return next[c];
      } else
        return nullptr;
    }
    Node(Node* parent, T last) : parent{parent}, last{last} {}
  };
  Node* root = new Node(nullptr, T());
  template <typename C>
  Node* insert_word(C word, need_int leaf_flag = 1) {
    Node* curr = root;
    for (T c : word) {
      if (!curr->next.contains(c)) {
        curr->next[c] = new Node(curr, c);
      }
      curr = curr->next[c];
    }
    curr->leaf = leaf_flag;
    return curr;
  }
  template <typename C>
  Node* jump_path(Node* node, C path) {
    for (T c : path) {
      if (node == nullptr) return node;
      node = node->jump(c);
    }
    return node;
  }
  template <typename C>
  bool contains_word(C word) {
    Node* res = jump_path(root, word);
    return res && res->leaf;
  }
};
template <need_int ALPHABETSIZE>
struct Basic_Char_Trie_Op {
  using T = char;
  template <typename Node>
  struct Info {};
  template <typename N>
  struct Next {
    N next[ALPHABETSIZE] = {};
    N& operator[](char i) { return next[i - 'a']; }
    bool contains(char i) { return operator[](i) != nullptr; }
  };
};
template <need_int ALPHABET_SIZE>
using CharTrie = Trie<Basic_Char_Trie_Op<ALPHABET_SIZE>>;
}  // namespace mytl
namespace mytl {
template <typename BaseTrie>
struct Corasick {
  struct Corasick_Op : BaseTrie::Op {
    using T = typename BaseTrie::Op::T;
    template <typename N>
    struct Info {
      N* next_leaf_d = nullptr;
      N* link_d = nullptr;
      typename BaseTrie::Op::template Next<N*> go_d;
    };
  };
  using MyTrie = Trie<Corasick_Op>;
  using Node = typename MyTrie::Node;
  using T = typename Corasick_Op::T;
  MyTrie trie;
  static Node* go(Node* node, T c) {
    if (!node->go_d.contains(c)) {
      if (node->next.contains(c)) {
        node->go_d[c] = node->next[c];
      } else if (node->parent == nullptr) {
        node->go_d[c] = node;
      } else {
        node->go_d[c] = go(link(node), c);
      }
    }
    return node->go_d[c];
  };
  static Node* link(Node* node) {
    if (node->link_d == nullptr) {
      if (node->parent == nullptr) {
        node->link_d = node;
      } else if (node->parent->parent == nullptr) {
        node->link_d = node->parent;
      } else {
        node->link_d = go(link(node->parent), node->last);
      }
    }
    return node->link_d;
  }
  static Node* next_leaf(Node* node) {
    if (node->next_leaf_d == nullptr) {
      if (node->parent == nullptr) {
        node->next_leaf_d = node;
      } else {
        if (link(node)->leaf) {
          node->next_leaf_d = link(node);
        } else {
          node->next_leaf_d = next_leaf(link(node));
          if (!node->next_leaf_d->leaf) {
            node->next_leaf_d = node;
          }
        }
      }
    }
    return node->next_leaf_d;
  }
  static vector<need_int> current_matches(Node* node) {
    vector<need_int> res;
    if (node->leaf) res.push_back(node->leaf);
    while (next_leaf(node) != node) {
      node = next_leaf(node);
      res.push_back(node->leaf);
    }
    return res;
  }
  Node* root = trie.root;
  template <typename C>
  Corasick(C dictionary) {
    need_int i = 0;
    for (auto word : dictionary) {
      trie.insert_word(word, ++i);
    }
  }
};
}  // namespace mytl
namespace mytl {
struct Point {
  ll x, y;
  Point(ll x, ll y) : x{x}, y{y} {};
  Point(pair<ll, ll> initPair) : x{initPair.first}, y{initPair.second} {};
  pair<ll, ll> getPair() { return {x, y}; }
  Point operator-() const { return {-x, -y}; }
  Point operator+() const { return {x, y}; }
  static ll sgn(ll x) { return (x > 0) - (x < 0); }
  Point operator*(const ll& operand) const {
    return {x * operand, y * operand};
  }
  Point operator+(const Point& operand) const {
    return {x + operand.x, y + operand.y};
  }
  Point operator-(const Point& operand) const {
    return {x - operand.x, y - operand.y};
  }
  ll operator*(const Point& operand) { return x * operand.y - y * operand.x; }
  ll direction(const Point& a, const Point& b) const {
    return sgn((a - *this) * (b - *this));
  };
};
ll distance_squared(const Point& a, const Point& b) {
  return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
double distance(const Point& a, const Point& b) {
  return sqrt(distance_squared(a, b));
}
ll cartesian_distance(const Point& a, const Point& b) {
  return abs(a.x - b.x) + abs(a.y - b.y);
}
bool inside(const vector<Point>& poly, const Point& point, bool strict) {
  ll prevdir = -2;
  for (ll i = 0; i < poly.size(); i++) {
    ll nexdindex = (i + 1) % poly.size();
    ll dir = poly[i].direction(poly[nexdindex], point);
    if (dir == 0) {
      if (strict) return false;
    } else {
      if (dir != prevdir && prevdir != -2) return false;
      prevdir = dir;
    }
  }
  return true;
}
}  // namespace mytl
namespace mytl {
template <class T>
struct Resetter;
template <class T>
Resetter<T>* global_resetter = new Resetter<T>;
template <class T>
struct Resetter {
  using State = pair<counter_type, T>;
  State* state = new State{0, T()};
  Resetter() {}
  Resetter(T value) { state = new State{0, value}; }
  void activate() { global_resetter<T> = this; }
  void reset(T value) { *state = State{state->first + 1, value}; }
  struct Variable {
    State state;
    State& parent = *global_resetter<T>->state;
    Variable() : state{*global_resetter<T>->state} {}
    Variable(T value) : state{global_resetter<T>->state->first, value} {}
    Variable(State st) : state{st} {}
    Variable(T value, State& parent) : state{parent->first, value} {};
    bool fresh() { return state.first >= parent.first; }
    void overwrite() { state = parent; }
    void refresh() {
      if (!fresh()) overwrite();
    }
    T get() {
      refresh();
      return state.second;
    }
    void survive() { state.first = parent.first; }
    void operator=(T new_value) {
      state.second = new_value;
      survive();
    }
  };
};
}  // namespace mytl
namespace mytl {
template <typename T>
T read(istream& is = cin) {
  T a;
  is >> a;
  return a;
}
template <typename T, typename Container = vector<T>>
vector<T> readValues(ll n, istream& is = cin) {
  vector<T> res;
  repeat(n, [&res]() { res.push_back(read<T>()); });
  return Container(res.begin(), res.end());
}
template <typename T>
void print(const T& x, ostream& os = cout) {
  os << x;
}
template <typename Container>
void printContainer(const Container& cont, ostream& os = cout) {
  os << "{";
  bool first = true;
  for (const auto& elem : cont) {
    if (!first) {
      os << ", ";
    } else {
      first = false;
    }
    print(elem, os);
  }
  os << "}";
}
}  // namespace mytl
namespace mytl {
template <typename T>
T power(T base, ll exponential, T unit = 1) {
  T res = unit;
  while (exponential > 0) {
    if (exponential % 2 == 1) res = res * base;
    base = base * base;
    exponential = exponential / 2;
  }
  return res;
}
template <typename T>
struct Pows2 : vector<T> {
  Pows2() {
    this->resize(300);
    this->operator[](0) = 1;
    for (ll i = 1; i < this->size(); i++) {
      this->operator[](i) = this->operator[](i) * 2;
    }
  }
};
template <typename T>
Pows2<T> powers2;
}  // namespace mytl
namespace mytl {
struct Modulo {
  static ll CURRENT_MOD;

 private:
  ll val;

 public:
  static Modulo inverse(Modulo x) { return power(x, CURRENT_MOD - 2); };
  Modulo(ll initVal) {
    assert(CURRENT_MOD != 0);
    if (-CURRENT_MOD < initVal && initVal < CURRENT_MOD) {
      val = initVal;
    } else {
      val = initVal % CURRENT_MOD;
    }
  }
  Modulo() : Modulo(0) {}
  Modulo& operator=(const Modulo&) = default;
  ll get() const {
    if (val >= 0)
      return val;
    else
      return val + CURRENT_MOD;
  }
  Modulo operator-() const { return Modulo(-val); };
  Modulo operator+() const { return Modulo(+val); };
  Modulo operator-(const ll& operand) const { return Modulo(val - operand); };
  Modulo operator+(const ll& operand) const { return Modulo(val + operand); };
  Modulo operator*(const ll& operand) const { return Modulo(val * operand); };
  Modulo operator/(const ll& operand) const {
    return Modulo(inverse(operand) * val);
  };
  Modulo operator-(const Modulo& operand) const {
    return Modulo(val - operand.get());
  };
  Modulo operator+(const Modulo& operand) const {
    return Modulo(val + operand.get());
  };
  Modulo operator*(const Modulo& operand) const {
    return Modulo(val * operand.get());
  };
  Modulo operator/(const Modulo& operand) const {
    return Modulo(inverse(operand) * val);
  };
};
ll Modulo::CURRENT_MOD = 0;
}  // namespace mytl
namespace mytl {
template <ll MOD>
struct TSModulo {
  friend class optional<TSModulo<MOD>>;

 private:
  ll val;

 public:
  static TSModulo inverse(TSModulo x) { return power(x, MOD - 2); };
  TSModulo(ll initVal) {
    if (-MOD < initVal && initVal < MOD) {
      val = initVal;
    } else {
      val = initVal % MOD;
    }
  }
  TSModulo() : TSModulo(0) {}
  TSModulo& operator=(const TSModulo&) = default;
  ll get() const {
    if (val >= 0)
      return val;
    else
      return val + MOD;
  }
  TSModulo operator-() const { return TSModulo(-val); };
  TSModulo operator+() const { return TSModulo(+val); };
  TSModulo operator-(const ll& operand) const {
    return TSModulo(val - operand);
  };
  TSModulo operator+(const ll& operand) const {
    return TSModulo(val + operand);
  };
  TSModulo operator*(const ll& operand) const {
    return TSModulo(val * operand);
  };
  TSModulo operator/(const ll& operand) const {
    return TSModulo(inverse(operand) * val);
  };
  TSModulo operator-(const TSModulo& operand) const {
    return TSModulo(val - operand.get());
  };
  TSModulo operator+(const TSModulo& operand) const {
    return TSModulo(val + operand.get());
  };
  TSModulo operator*(const TSModulo& operand) const {
    return TSModulo(val * operand.get());
  };
  TSModulo operator/(const TSModulo& operand) const {
    return TSModulo(val * inverse(operand));
  };
};
template <ll MOD>
struct optional<TSModulo<MOD>> {
  ll val = off_value;
  static const ll off_value = -MOD - 1;
  bool has_value() const { return val != off_value; }
  void set(const TSModulo<MOD>& other) { val = other.val; }
  TSModulo<MOD> value() const {
    assert((has_value()));
    if (!has_value()) {
      TSModulo<MOD>* dummy = nullptr;
      return *dummy;
    }
    return TSModulo<MOD>(val);
  }
  optional() {}
  optional<TSModulo<MOD>>& operator=(const TSModulo<MOD>& other) {
    set(other);
    return *this;
  }
  optional(const TSModulo<MOD>& other) { set(other); }
};
using Mod107 = TSModulo<1000000007LL>;
}  // namespace mytl
namespace mytl {
template <typename C, typename Arg, typename R>
function<R(Arg)> __memoize(R (*fn)(Arg)) {
  C table;
  return [fn, table](Arg arg) mutable -> R {
    if (!table[arg].has_value()) {
      table[arg].set(fn(arg));
    }
    return table[arg].value();
  };
}
template <template <typename, typename, typename...> typename C, typename Arg,
          typename R>
function<R(Arg)> memoize(R (*fn)(Arg)) {
  return __memoize<C<Arg, optional<R>>, Arg, R>(fn);
}
template <typename R>
function<R(ll)> quick_memoize(R (*fn)(ll)) {
  return __memoize<TwoWayLazyVector<optional<R>>, ll, R>(fn);
}
template <typename R>
function<R(ll, ll)> quick_memoize(R (*fn)(ll, ll)) {
  TwoWayLazyVector<TwoWayLazyVector<optional<R>>> table;
  return [fn, table](ll p1, ll p2) mutable -> R {
    if (!table[p1][p2].has_value()) {
      table[p1][p2].set(fn(p1, p2));
    }
    return table[p1][p2].value();
  };
}
}  // namespace mytl
namespace mytl {
template <class Op>
struct IntervalTree : Op::Range {
  using Range = typename Op::Range;
  using T = typename Op::T;
  using Change = typename Op::Change;
  using Range::inside;
  using Range::intersect;
  using Range::leftHalf;
  using Range::rightHalf;
  using Range::singleton;
  IntervalTree *left_child = NULL, *right_child = NULL;
  T partial;
  Change pending = Op::identity();
  IntervalTree(Range range) : Range(range), partial{Op::initial(range)} {};
  T query(Range range, Change change) { return query_(range, change).first; }
  void add(Change change) { pending = Op::push(pending, change); }
  void prepare() {
    if (!singleton()) {
      if (left_child == NULL) left_child = (new IntervalTree(leftHalf()));
      if (right_child == NULL) right_child = (new IntervalTree(rightHalf()));
      left_child->add(pending);
      right_child->add(pending);
    }
    partial = Op::apply(*this, partial, pending);
    pending = Op::identity();
  }
  pair<T, T> query_(Range range, Change change) {
    prepare();
    if (inside(range)) {
      add(change);
      prepare();
      return {partial, Op::zero()};
    }
    if (!intersect(range)) {
      return {Op::zero(), partial};
    }
    auto from_left = left_child->query_(range, change);
    auto from_right = right_child->query_(range, change);
    auto needed = Op::reduce(from_left.first, from_right.first),
         rest = Op::reduce(from_left.second, from_right.second);
    partial = Op::reduce(needed, rest);
    return {needed, rest};
  }
  T build_from(const function<T(ll)>& getter) {
    prepare();
    pending = Op::identity();
    if (singleton())
      partial = getter(this->l);
    else
      partial = Op::reduce(left_child->build_from(getter),
                           right_child->build_from(getter));
    return partial;
  }
};
template <typename Op>
class SegmentTree {
 public:
  const pair<ll, ll> range;

 private:
  vector<typename Op::T> t;
  vector<typename Op::Change> d;
  ll n;
  ll h;
  void __calc(ll p, ll k) {
    t[p] = Op::apply(k, Op::reduce(t[p * 2], t[p * 2 + 1]), d[p]);
  }
  void __apply(ll p, typename Op::Change value, ll k) {
    t[p] = Op::apply(k, t[p], value);
    if (p < n) d[p] = Op::push(d[p], value);
  }
  void __build(ll l, ll r) {
    ll k = 2;
    l += n;
    r += n - 1;
    for (; l > 1; k *= 2) {
      l /= 2;
      r /= 2;
      for (ll i = r; i >= l; i--) __calc(i, k);
    }
  }
  void __push(ll l, ll r) {
    ll s = h;
    ll k = 1 << (h - 1);
    l += n;
    r += n - 1;
    for (; s > 0; s--, k /= 2) {
      for (ll i = l >> s; i <= r >> s; i++) {
        __apply(i * 2, d[i], k);
        __apply(i * 2 + 1, d[i], k);
        d[i] = Op::identity();
      }
    }
  }
  void __modify(ll l, ll r, typename Op::Change value) {
    __push(l, l + 1);
    __push(r - 1, r);
    ll l0 = l, r0 = r, k = 1;
    l += n;
    r += n;
    for (; l < r; l /= 2, r /= 2, k *= 2) {
      if (l & 1) __apply(l++, value, l);
      if (r & 1) __apply(--r, value, k);
    }
    __build(l0, l0 + 1);
    __build(r0 - 1, r0);
  }
  typename Op::T __query(ll l, ll r) {
    __push(l, l + 1);
    __push(r - 1, r);
    typename Op::T resl = Op::zero(), resr = Op::zero();
    l += n;
    r += n;
    for (; l < r; l /= 2, r /= 2) {
      if (l & 1) resl = Op::reduce(resl, t[l++]);
      if (r & 1) resr = Op::reduce(t[--r], resr);
    }
    return Op::reduce(resl, resr);
  }

 public:
  SegmentTree(pair<ll, ll> range, const function<typename Op::T(ll)>& getter)
      : range{range} {
    n = range.second - range.first + 1;
    t.resize(n * 2);
    d.resize(n, Op::identity());
    for (ll i = 0; i < n; i++) {
      t[i + n] = getter(i + range.first);
    }
    for (ll i = n - 1; i > 0; i--) t[i] = t[i * 2] + t[i * 2 + 1];
    h = 0;
    ll new_n = n;
    while (new_n > 0) {
      h++;
      new_n /= 2;
    }
  }
  typename Op::T query(pair<ll, ll> query_range) {
    assert(range.first <= query_range.first &&
           query_range.second <= range.second);
    return __query(query_range.first - range.first,
                   query_range.second - range.first + 1);
  }
  typename Op::T query_single(ll query_point) {
    return query({query_point, query_point});
  }
  void modify(pair<ll, ll> modify_range, typename Op::Change value) {
    assert(range.first <= modify_range.first &&
           modify_range.second <= range.second);
    __modify(modify_range.first - range.first,
             modify_range.second - range.first + 1, value);
  }
  void modify_single(ll modify_point, typename Op::Change value) {
    return modify({modify_point, modify_point}, value);
  }
};
template <typename T_, typename Range_>
struct Add_Sum {
  using Range = Range_;
  using T = T_;
  using Change = T_;
  static Change identity() { return 0; }
  static T zero() { return 0; }
  static T initial(Range r) { return zero(); }
  static T reduce(T a, T b) { return a + b; }
  static T apply(Range r, T a, Change c) { return a + r.span() * c; }
  static Change push(Change a, Change b) { return a + b; }
};
template <typename T_, typename Range_>
struct Multiply_Sum {
  using Range = Range_;
  using T = T_;
  using Change = T_;
  static Change identity() { return 1; }
  static T zero() { return 0; }
  static T initial(Range r) { return r.span() * 1; }
  static T reduce(T a, T b) { return a + b; }
  static T apply(Range r, T a, Change c) { return a * c; }
  static Change push(Change a, Change b) { return a * b; }
};
}  // namespace mytl
namespace mytl {
template <typename T, T (*f)(T, T)>
struct Tracker : optional<T> {
  void update(const T& x) {
    if (optional<T>::has_value()) {
      optional<T>::set(f(optional<T>::value(), x));
    } else {
      optional<T>::set(x);
    }
  }
};
template <typename T>
T min(T a, T b) {
  return std::min(a, b);
}
template <typename T>
T max(T a, T b) {
  return std::max(a, b);
}
}  // namespace mytl
string A, B;
need_int d[5000][5000][2];
need_int rek(need_int i, need_int j, bool started) {
  if (min(i, j) < 0) return 0;
  if (d[i][j][started] != -1) {
    return d[i][j][started];
  } else {
    need_int& kulcs = d[i][j][started];
    need_int res = 0;
    res =
        max(rek(i - 1, j, started) - started, rek(i, j - 1, started) - started);
    res = max(res, 0);
    if (A[i] == B[j]) res = max(res, rek(i - 1, j - 1, true) + 2);
    kulcs = res;
    return res;
  }
}
MAIN main() {
  ios_base::sync_with_stdio(false);
  for (ll i = 0; i < 5000; i++) {
    for (ll j = 0; j < 5000; j++) {
      d[i][j][0] = d[i][j][1] = -1;
    }
  }
  need_int n, m;
  cin >> n >> m >> A >> B;
  cout << rek(n - 1, m - 1, false) << endl;
}
