Problem:
Score : 500 points

Problem Statement

You are given two integer sequences S and T of length N and M, respectively, both consisting of integers between 1 and 10^5 (inclusive).

In how many pairs of a subsequence of S and a subsequence of T do the two subsequences are the same in content?

Here the subsequence of A is a sequence obtained by removing zero or more elements from A and concatenating the remaining elements without changing the order.

For both S and T, we distinguish two subsequences if the sets of the indices of the removed elements are different, even if the subsequences are the same in content.

Since the answer can be tremendous, print the number modulo 10^9+7.

Constraints

1 \leq N, M \leq 2 \times 10^3

The length of S is N.

The length of T is M.

1 \leq S_i, T_i \leq 10^5

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M
S_1 S_2 ... S_{N-1} S_{N}
T_1 T_2 ... T_{M-1} T_{M}

Output

Print the number of pairs of a subsequence of S and a subsequence of T such that the subsequences are the same in content, modulo 10^9+7.

Sample Input 1

2 2
1 3
3 1

Sample Output 1

3

S has four subsequences: (), (1), (3), (1, 3).

T has four subsequences: (), (3), (1), (3, 1).

There are 1 \times 1 pair of subsequences in which the subsequences are both (), 1 \times 1 pair of subsequences in which the subsequences are both (1), and 1 \times 1 pair of subsequences in which the subsequences are both (3), for a total of three pairs.

Sample Input 2

2 2
1 1
1 1

Sample Output 2

6

S has four subsequences: (), (1), (1), (1, 1).

T has four subsequences: (), (1), (1), (1, 1).

There are 1 \times 1 pair of subsequences in which the subsequences are both (), 2 \times 2 pairs of subsequences in which the subsequences are both (1), and 1 \times 1 pair of subsequences in which the subsequences are both (1,1), for a total of six pairs.
Note again that we distinguish two subsequences if the sets of the indices of the removed elements are different, even if the subsequences are the same in content.

Sample Input 3

4 4
3 4 5 6
3 4 5 6

Sample Output 3

16

Sample Input 4

10 9
9 6 5 7 5 9 8 5 6 7
8 6 8 5 5 7 9 9 7

Sample Output 4

191

Sample Input 5

20 20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Sample Output 5

846527861

Be sure to print the number modulo 10^9+7.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <complex>
#include <vector>
#include <list>
#include <queue>
#include <deque>
#include <stack> 
#include <set>
#include <map>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
using edge = struct {ll to; ll cost;};
using point = struct {ll x; ll y;};
typedef string str;
typedef std::pair<ll,ll> pl;
typedef std::pair<ll,pl> pl3;
typedef std::map<string, ll> msl;
typedef std::map<char, ll> mcl;
typedef std::map<ll, ll> mll;
typedef std::vector<ll> vl;
typedef std::vector<pl> vpl;
typedef std::vector<point> vxy;
typedef std::vector<pl3> vpl3;
typedef std::priority_queue<ll> pq;
typedef std::priority_queue<ll, vl, greater<ll>> pql; // priority queue taking from the lower value.
typedef std::vector<edge> gr;
const ll MOD = 1e9 + 7;
// const ll MOD = 998244353;
const ll INF = MOD * MOD;
const long double EPS = 1e-9;
const long double PI = 3.14159265358979323846;

#define rep(i, n) for(ll (i) = 0; (i) < (n) ; (i)++ )
#define revrep(i, n) for(ll (i) = n - 1; (i) >= 0 ; (i)--)
#define For(i, a, b) for(ll (i) = (a); (i) < (b) ; (i)++ )
#define revFor(i, b, a) for(ll (i) = (b) - 1; (i) >= (a) ; (i)--)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define isUpper(c) ('a' - c > 0)
#define isNum(c) (0 <= (c) - '0' && (c) - '0' <= 9)
#define toLower(c) char((c)+0x20)
#define toUpper(c) char((c)-0x20)
#define pb push_back
#define mp make_pair
#define pr(a) cout << (a)
#define prl(a) cout << (a) << endl
#define prl2(a,b) cout << (a) << " " << (b) << endl
#define prl3(a,b,c) cout << (a) << " " << (b) << " " << (c) << endl
#define prl4(a,b,c,d) cout << (a) << " " << (b) << " " << (c) << " " << (d) << endl
#define prs(a) cout << (a) << " "
#define yn(condition) if ((condition)) prl("Yes"); else prl("No");
#define YN(condition) if ((condition)) prl("YES"); else prl("NO");
#define in1(a) cin >> (a)
#define in2(a,b) cin >> (a) >> (b)
#define in3(a,b,c) cin >> (a) >> (b) >> (c)
#define in4(a,b,c,d) cin >> (a) >> (b) >> (c) >> (d)
#define e1 first
#define e2 second
#define ctol(c) ll((c)) - ll('0')
#define ltos(n) to_string((n))
#define items(kv, v) for(auto &(kv): (v))
#define ndig(N, n) ctol(ll(ltos((N))[ll(ltos((N)).length()) - (n)]))
#define rsort(a,n) sort(a,a+n,greater<>())
#define Forchar(c,a,z) for(char (c) = (a); (c) <= (z); (c)++)
#define cntchar(s,c) count(all((s)), c)
#define substring(s, start, end) s.substr((start), (end) - (start) + 1)
#define prl_nd(num, digits) cout << fixed << setprecision(digits) << (num) << endl;
#define XOR(a, b) (a)^(b)
#define prl_time(s) prl3("Elapsed Time:", 1000.0 * (clock() - s) / CLOCKS_PER_SEC, "[ms]");
#define char_to_str(c) string(1, (c))
#define bin_expression(n, dig) bitset<(dig)>(n)
#define DEBUG(x) cerr<<#x<<": "<<(x)<<endl
#define DEBUG_VEC(v) cerr<<#v<<": ";rep(__i,(v).size())cerr<<((v)[__i])<<", ";cerr<<endl

struct MaxFlow {
    struct F_edge {
        ll to, rev, capacity;
        F_edge(ll to, ll rev, ll capacity) : to(to), rev(rev), capacity(capacity) {}
    };

    typedef vector<F_edge> F_edges;
    vector<F_edges> graph;
    ll n_vertex;
    // level is the shortest path to get a given node from the source node.
    vl level, iter;

    MaxFlow(ll n_vertex) : n_vertex(n_vertex) {graph.resize(n_vertex);}

    void add_edge(ll from, ll to, ll capacity) {
        graph[from].pb({to, ll(graph[to].size()), capacity});
        graph[to].pb({from, ll(graph[from].size()) - 1, 0});
    }

    void bfs(ll source){
        level = vl(n_vertex, -1); level[source] = 0;
        queue<ll> q; q.push(source);
        while (!q.empty()) {
            ll vertex = q.front(); q.pop();
            rep(i, graph[vertex].size()){
                ll target = graph[vertex][i].to;
                ll cap_target = graph[vertex][i].capacity;
                // if the flow can be into the target node, implement below.
                if (cap_target > 0 && level[target] < 0){
                    level[target] = level[vertex] + 1;
                    q.push(target);
                }
            }
        }
    }

    ll dfs(ll vertex, ll sink, ll flow) {
        if (vertex == sink) return flow;
        for(ll &i = iter[vertex]; i < graph[vertex].size(); i++){
            ll target = graph[vertex][i].to; ll cap_target = graph[vertex][i].capacity;
            ll rev_target = graph[vertex][i].rev;
            // if capasitiy is not full yet and target is farther,
            // then assign current flow 
            if (cap_target > 0 && level[vertex] < level[target]) {
                ll d = dfs(target, sink, min(cap_target, flow));
                if (d > 0){ // if the flow successfully reaches the sink, reduce the flow from the capacity 
                    graph[vertex][i].capacity -= d;
                    graph[target][rev_target].capacity += d;
                    return d;
                }
            }
        }
        return 0;
    }

    ll dinic(ll source, ll sink) {
        ll flow = 0;
        while (true) {
            bfs(source);
            // if there is no path leading to the sink, the maximum flow is 0.
            if (level[sink] < 0) return flow;
            iter = vl(n_vertex, 0); ll f;
            while ((f = dfs(source, sink, INF)) > 0) flow += f;
        }
    }
};

class UnionFind {
    vl parents, set_size;
public:
    UnionFind(){}
    UnionFind(ll n){
        parents = set_size = vl(n);
        rep(i, n) {parents[i] = i; set_size[i] = 1LL;}
    }

    ll root_find(ll x){
        if (parents[x] == x) return x;
        return parents[x] = root_find(parents[x]);
    }

    void unite(ll x, ll y){
        x = root_find(x); y = root_find(y);
        if (x == y) return;
        if (set_size[x] < set_size[y]){
            parents[y] = x; set_size[x] += set_size[y];
        }else{
            parents[x] = y; set_size[y] += set_size[x];
        }
    }

    bool is_same(ll x, ll y) {// connected or not
        return root_find(x) == root_find(y);
    }

    ll size(ll x) {
        return set_size[root_find(x)];
    }
};

/*
class LCA{
public:
    ll N, logN;
    vl depth, len;
    gr tree[200005]; // global declaration later.
    vector<vl> parents;

    LCA(ll n){
        N = n;
        logN = 0;
        while (N > (1LL << logN)) logN++;
        depth = vl(N); len = vl(N);
        parents = vector<vl>(logN, vl(N));
        init(0, -1, 0, 0);
        build();
    }

    void init(ll source, ll parent, ll d, ll l){
        depth[source] = d;
        parents[0][source] = parent;
        len[source] = l;
        rep(i, tree[source].size()){
            ll target = tree[source][i].to;
            ll cost = tree[source][i].cost;
            if (target == parent) continue;
            init(target, source, d + 1, cost + l);
        }
    }

    void build(){
        rep(k, logN - 1) rep(n, N){
            // if there is no parent, -1.
            // otherwise, the parent of the parent is the parent.
            if (parents[k][n] < 0) parents[k + 1][n] = -1;
            else parents[k + 1][n] = parents[k][parents[k][n]];
        }
    }

    ll query(ll u, ll v){
        if (depth[u] > depth[v]) swap(u, v);
        rep(k, logN) if ((depth[v] - depth[u]) >> k & 1) v = parents[k][v];
        if (u == v) return u;

        revrep(k, logN){
            if (parents[k][u] != parents[k][v]){
                u = parents[k][u]; v = parents[k][v];
            }
        }
        return parents[0][u];
    }

    ll distance(ll u, ll v){
        ll w = query(u, v);
        return len[u] + len[v] - 2 * len[w];
    }

};
*/

struct BIT{
    ll n; vl tree_dat;
    BIT(ll n): tree_dat(n + 1, 0), n(n){};

    //       x: 1001 1010  1100 1011 1101  1111
    // x & - x: 0001 0010  0100 0001 0001  0001
    //      ->: 1010 1100 10000 1100 1100 10000

    ll update_func(ll val, ll dat){
        // if maximum -> max(val, dat)
        // return max(val, dat);
        // if cumulative sum
        return val + dat;
    }

    ll query(ll i){
        /*
        e.g.) i = 10101
        itr1. 10101 -> 10100 
        itr2. 10100 -> 10000
        itr3. 10000 -> 00000 (break)
        */
        ll ret = 0;
        for (ll j = i - 1; j >= 0; j = (j & (j + 1)) - 1){
            ret = update_func(ret, tree_dat[j]);
        }
        return ret;
    }

    void update(ll i, ll val){
        /*
        e.g.) i = 10101, n = 11111
        itr1. 10101 ->  10110 
        itr2. 10110 ->  11000
        itr3. 11000 -> 100000 (break)
        */
        for(ll j = i; j < n; j |= j + 1){
            tree_dat[j] = update_func(val, tree_dat[j]);
        }
    }
};

ll gcd(ll m, ll n){
    ll a = max(m, n);
    ll b = min(m, n);
    while(b != 1 && b != 0){ a %= b; swap(a, b);}
    return b == 1 ? 1 : a;
}

ll lcm(ll m, ll n){ return m / gcd(m, n) * n;}

ll power_mod(ll a, ll power, ll mod){
    ll value = 1;
    while(power != 0){
        if(power & 1) value = (value * a) % mod;
        a = (a * a) % mod;
        power = power >> 1;
    }
    return value % mod;
}

ll modinv(ll a, ll mod){
    return power_mod(a, mod - 2, mod);
}

ll power_normal(ll a, ll power){
    ll value = 1;
    while(power != 0){
        if(power & 1) value = value * a;
        a = a * a;
        power = power >> 1;
    }
    return value;
}

ll comb_memo[55][55];

ll pascal_triangle(ll n){
    comb_memo[0][0] = 1;
    For(i, 1, n + 1) rep(j, i + 1){
        comb_memo[i][j] += comb_memo[i - 1][j];
        if (j > 0) comb_memo[i][j] += comb_memo[i - 1][j - 1];
    }
}

ll combination(ll n, ll r, ll mod){
    if (n == r && n == 0) return 1;
    else if (n <= 0 || r < 0 || r > n) return 0;
    ll numerator = 1;
    ll denomenator = 1;
    for(ll i = 0; i < r ; i++){
        (numerator *= ll(n - i)) %= mod;
        (denomenator *= modinv(i + 1, mod)) %= mod;
    }

    return (numerator * denomenator) % mod;
}

ll combination_memo(ll n, ll r, ll pre, ll mod){
    // pre = nCr-1
    // return nCr
    if (n == r && n == 0) return 1;
    else if (n <= 0 || r < 0 || r > n) return 0;
    ll numerator = ll(n - r + 1) % mod;
    ll denomenator = modinv(r, mod) % mod;
    ll val = (numerator * denomenator) % mod;
    val *= pre;
    return val % mod;
}

ll combination_no_mod(ll n, ll r){
    if (n == r && n == 0) return 1;
    else if (n <= 0 || r < 0 || r > n) return 0;
    ll numerator = 1;
    ll denomenator = 1;
    for(ll i = 0; i < r ; i++){
        numerator *= n - i;
        denomenator *= i + 1;
        ll g = gcd(numerator, denomenator);
        numerator /= g; denomenator /= g;
    }

    return numerator;
}

ld log_combination(ll n, ll r){
    if (n == r && n == 0) return 0;
    else if (n <= 0 || r < 0 || r > n) return -INF;
    ld val = 0;
    for(ll i = 0; i < r ; i++){
        val += log(n - i);
        val -= log(i + 1);
    }

    return val;
}

ll bin_search(ll key, ll A[], ll left, ll right){
    // return the index idx where A[idx] = key.
    // A[left] is start and A[right] is end..
    // In other words, A[right], not A[right - 1], must be defined.
    while(right >= left){
        ll mid = left + (right - left) / 2;
        if (A[mid] == key) return mid;
        else if (A[mid] > key) right = mid - 1;
        else if (A[mid] < key) left = mid + 1;
    }
    return -1;
}

/*
ll bin_search_temp(ll left, ll right, callable judge){
    while(right > left){
        // when seeking lower bound
        ll mid = (right + left) / 2;
        if (judge(mid)) right = mid;
        else left = mid + 1;
        // when seeking upper bound
        ll mid = (right + left + 1) / 2;
        if (judge(mid)) left = mid;
        else right = mid - 1;
    }

    return right;
}

trinary_search

ld left = 0; ld right = p;
while(abs(right - left) > EPS){
    ld left2 = (2 * left + right) / 3.0;
    ld right2 = (left + 2 * right) / 3.0;
    ld f1 = tak_func(left2);
    ld f2 = tak_func(right2);
    if (f1 <= f2) right = right2;
    else if (f2 <= f1) left = left2;
}

*/

ll lower_bound_bin_search_temp(ll key, ll A[], ll left, ll right){
    // Pay attention to the return value -1.
    // For example, sometimes you may want the value right instead of -1.
    if (A[left] >= key) return left;
    ll mid = left + (right - left) / 2;

    while(right >= left){
        mid = left + (right - left) / 2;
        if (mid == left) {
            if (A[left] < key && key <= A[left + 1]) return left + 1;
            else return -1;
        }
        if (A[mid - 1] < key && key <= A[mid]) return mid;
        else if (A[mid - 1] >= key) right = mid - 1;
        else if (A[mid] < key) left = mid;
    }

    return -1; // all the elements < key
}

ll inf_bin_search_temp(ll key, ll A[], ll left, ll right){
    // Pay attention to the return value -1.
    // For example, sometimes you may want the value right instead of -1.
    if (A[left] > key) return left;
    ll mid = left + (right - left) / 2;

    while(right >= left){
        mid = left + (right - left) / 2;
        if (mid == left) {
            if (A[left] <= key && key < A[left + 1]) return left + 1;
            else return -1;
        }
        if (A[mid - 1] <= key && key < A[mid]) return mid;
        else if (A[mid - 1] > key) right = mid - 1;
        else if (A[mid] <= key) left = mid;
    }

    return -1; // all the elements <= key
}

ll upper_bound_bin_search_temp(ll key, ll A[], ll left, ll right){
    // Pay attention to the return value -1.
    // For example, sometimes you may want the value left instead of -1.
    if (A[right] <= key) return right;
    ll mid = left + (right - left) / 2;

    while(right >= left){
        mid = left + (right - left) / 2;
        if (mid == right) {
            if (A[right - 1] <= key && key < A[right]) return right - 1;
            else return -1;
        }
        if (A[mid] <= key && key < A[mid + 1]) return mid;
        else if (A[mid] > key) right = mid;
        else if (A[mid + 1] <= key) left = mid + 1;
    }

    return -1; // all the elements > key
}

ll sup_bin_search_temp(ll key, ll A[], ll left, ll right){
    // Pay attention to the return value -1.
    // For example, sometimes you may want the value left instead of -1.
    if (A[right] < key) return right;
    ll mid = left + (right - left) / 2;

    while(right >= left){
        mid = left + (right - left) / 2;
        if (mid == right) {
            if (A[right - 1] < key && key <= A[right]) return right - 1;
            else return -1;
        }
        if (A[mid] < key && key <= A[mid + 1]) return mid;
        else if (A[mid] >= key) right = mid;
        else if (A[mid + 1] < key) left = mid + 1;
    }

    return -1; // all the elements >= key
}

ll bin_search_vector(ll key, vl v, ll left, ll right){
    // return the index idx where v[idx] = key.
    // v[left] is start and v[right] is end..
    // In other words, v[right], not v[right - 1], must be defined.
    while(right >= left){
        ll mid = left + (right - left) / 2;
        if (v[mid] == key) return mid;
        else if (v[mid] > key) right = mid - 1;
        else if (v[mid] < key) left = mid + 1;
    }
    return -1;
}

ll lower_bound_bin_search_vector(ll key, vl v){
    // the return value N satisfies
    // v[N - 1] < key <= v[N]
    // N == -1 if all the elements < key
    return lower_bound(all(v), key) - v.begin();
}

ll inf_bin_search_vector(ll key, vl v){
    // the return value N satisfies
    // v[N - 1] <= key < v[N] <= key + 1
    // N == -1 if all the elements <= key
    return lower_bound(all(v), key + 1) - v.begin();
}

ll upper_bound_bin_search_vector(ll key, vl v){
    // the return value N satisfies
    // v[N] <= key < v[N + 1]
    // N == -1 if all the elements > key
    return upper_bound(all(v), key) - v.begin(); // (- 1)
}

ll sup_bin_search_vector(ll key, vl v){
    // the return value N satisfies
    // v[N] <= key - 1 < key <= v[N + 1]
    // N == -1 if all the elements >= key
    return upper_bound(all(v), key - 1) - v.begin() - 1;
}

ll fact(ll n){
    if (n == 0) return 1;
    return n * fact(n - 1);
}

bool is_prime(ll n){
    if (n <= 1) return false;
    for(ll i = 2; i * i <= n; i++){
        if (n % i == 0) return false;
    }
    return true;
}

ll bool_sum(ll a1, ll a2){
    if (a1 == 1 || a2 == 1) return 1;
    return 0;
}

mll prime_factorization(ll n){
    ll i = 2;
    mll table;
    while(i * i <= n){
        while(n % i == 0){
            table[i] ++;
            n /= i;
        }
        i++;
    }
    if (n > 1) table[n] = 1;
    return table;
}

vl divisor_table(ll n){
    vl table;
    ll i = 1;
    while(i * i <= n){
        if (n % i == 0){
            table.pb(i);
            if (i * i != n) table.pb(n / i);
        }
        i++;
    }

    sort(all(table));

    return table;
}

ll char_to_idx(char c){
    ll idx = 0;
    Forchar(cc, 'a', 'z'){
        if (c == cc) return idx;
        else idx ++;
    }
}

bool is_cross(ll x1, ll y1, ll x2, ll y2, ll x3, ll y3, ll x4, ll y4){
    ll val1 = (x1 - x2) * (y3 - y1) + (y1 - y2) * (x1 - x3);
    ll val2 = (x1 - x2) * (y4 - y1) + (y1 - y2) * (x1 - x4);
    ll val3 = (x3 - x4) * (y1 - y3) + (y3 - y4) * (x3 - x1);
    ll val4 = (x3 - x4) * (y2 - y3) + (y3 - y4) * (x3 - x2);

    return val1 * val2 < 0 && val3 * val4 < 0;
}

ld space_of_triangle(ll x1, ll y1, ll x2, ll y2, ll x3, ll y3){
    ll v1 = x2 - x1; ll u1 = y2 - y1;
    ll v2 = x3 - x1; ll u2 = y3 - y1;
    ld s = ld(v1 * u2 - u1 * v2) / ld(2);
    return abs(s);
}

ll next_combination(ll sub){
    /*
    ll n, k; ll bit = (1 << k) - 1;
    for (; bit < (1 << n); bit = next_combination(bit)){
        bool ith = bit & (1 << i);
        procedures...
    }
    */
    ll x = sub & -sub, y = sub + x;
    return (((sub & ~y) / x) >> 1) | y; 
}

vl z_algorithm(str s){
    ll n = s.length(); vl res(n);
    res[0] = n;
    ll i1 = 1, i2 = 0;

    while(i1 < n){
        while (i1 + i2 < n && s[i2] == s[i1 + i2]) ++i2;
        res[i1] = i2; if (i2 == 0){++i1; continue;}
        ll i3 = 1;
        while (i1 + i3 < n && i3 + res[i3] < i2){res[i1 + i3] = res[i3]; ++i3;}
        i1 += i3, i2 -= i3;
    }
    return res;
}

ll big_number_mod(str s, ll mod){
    ll l = s.length(); ll idx = 0;
    ll val = 0; ll tenth = 1;
    while (idx < l){
        ll m = ctol(s[l - 1 - idx]);
        val += (m * tenth) % mod; val %= mod;
        tenth *= 10; tenth %= mod; idx++;
    }

    return val;
}

ll string_to_ll(str s){
    ll l = s.length(); ll idx = 0;
    ll val = 0; ll tenth = 1;
    while (idx < l){
        ll m = ctol(s[l - 1 - idx]);
        val += (m * tenth);
        tenth *= 10; idx++;
    }

    return val;
}

str reflected_string(str s){
    str t, u; ll n = s.length();
    t = s; reverse(all(t));
    u = substring(t, 0, n - 2) + s + substring(t, 1, n - 1);
    return u;
}

ld distance_between_point_line(ll xl1, ll yl1, ll xl2, ll yl2, ll xp, ll yp){
    ll a = yl2 - yl1;
    ll b = - xl2 + xl1;
    ll c = - a * xl2 - b * yl2;
    return abs(ld(a * xp + b * yp + c)) / ld(sqrt(a * a + b * b));
}

/*
const ll N_VERTEX = 310;
ll a, b, t;
ll dist[N_VERTEX][N_VERTEX];

void warshall_floyd(ll n){
    // rep(i, n) rep(j, n) dist[i][j] = INF * (i != j);
    rep(k, n) rep(i, n) rep(j, n) dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}

int main(void){
    in2(n, m);
    rep(i, n) rep(j, n) dist[i][j] = INF * (i != j);
    rep(i, m){
        in3(a, b, t);
        a--; b--;
        dist[a][b] = t;
        dist[b][a] = t;
    }

    warshall_floyd(n);
}

const ll N_VERTEX = 310;
gr graph[N_VERTEX];
ll dist[N_VERTEX], a, b, t, n, m;

void dijkstra(ll start, ll n) {
    priority_queue<pl, vector<pl>, greater<pl>> edge_costs;
    fill(dist, dist + n, INF);
    dist[start] = 0;
    edge_costs.push(pl(0, start));

    while (!edge_costs.empty()) {
        pl edge_cost = edge_costs.top();
        edge_costs.pop();
        ll idx = edge_cost.second;
        ll cost = edge_cost.first;
        if (dist[idx] < cost) continue;

        rep(i, graph[idx].size()){
            edge e = graph[idx][i];
            if (dist[e.to] > dist[idx] + e.cost){
                dist[e.to] = dist[idx] + e.cost;
                edge_costs.push(pl(dist[e.to], e.to));
            }
        }
    }
}

int main(void){
    in2(n, m);
    rep(i, m){
        in3(a, b, t);
        a--; b--;
        G[a].pb({b, t});
        G[b].pb({a, t});
    }

    dijkstra(0, n);
}


# ABC061D

bool bellman_ford(ll start, ll n, ll goal){
    // if there is a closed circuit, it returns false. (when goal == -1)
    // if the distance to goal cannot be obtained, it returns false (when goal != -1)
    fill(dist, dist + n, INF);
    dist[start] = 0;
    rep(i, n) rep(v, n) rep(k, graph[v].size()){
        edge e = graph[v][k];
        if (dist[e.to] > dist[v] + e.cost){
            dist[e.to] = dist[v] + e.cost;
            if (i == n - 1 && (e.to == goal || goal == -1)) return false;
        }
    }
    return true;
}

*/

/*
    # 1. The usage of map pair
    map<pl, ll> cnt;
    cnt[{i, j}] = 0;
    items(kv, cnt){
        prl2(kv.first, kv.second);
    }

    # 2. The usage of next_permutation and combination (factorial search)
    ll a[8];
    rep(i, 8) a[i] = i;
    sort(a, a + 8);
    do{
    }while(next_permutation(a, a+n));

    // here, combination
    ll n, r;
    ll i1, i2, ..., ir;
    For(i1, n - r, n) For(i2, n - r - 1, i1) ... For(ir, n - 2 * r + 1, irr){ process;}

    # 3. bit search
    ll n;
    in1(n);
    const ll base = 3;
    ll upper = power_normal(base, n);
    
    rep(i, upper){
        ll tmp = i;
        rep(j, n){
            rep(k, base) if (tmp % base == k) prl(k);
            tmp /= base;
        }
    }

    # 4. imos method
    // used when we would like to count the number which
    // shows how many times the numbers between l and r belongs to smt.
    // This method is composed of three process.
    ll n, m, s[MAX_M], l, r;
    in2(n, m);
    rep(i, m) s[i] = 0;

    // 1st step
    rep(i, n){
        in3(l, r, c);
        l--; r--; // if l starts from 1.
        s[l] += c; s[r + 1] -= c;
    }

    // 2nd step
    rep(i, m - 1) s[i + 1] += s[i];
    // 3rd step: judgement...

    #5. shakutori method (syakutori)
    // 1. strech right side while the condition is met.
    // 2. renew the answer
    // 3. increments left side
    // 4. Back to 1. (l <= r must be satisfied all the time.)

    ll l = 0; ll r = 0;
    while (l < n){
        r = max(r, l);
        if (l == r) r++;
        while(r < n && cond) r++;
        answer += r - l; l++;
    }
    prl(answer);

    #6. priority queue

    pq q;
    ll answer = 0;
    ll v;

    rep(i, n) q.push(a[i]);
    rep(i, m){
        v = q.top(); q.pop(); // get the top value and dump the value from queue
        v /= 2; q.push(v); // add the new value
    }

    while(!q.empty()){
        answer += q.top();
        q.pop();
    }

    #7. The shortest path between the k-th edge and another edge (Tree)
    ll depth[MAX_N];
    gr tree[MAX_N];

    void path(ll source, ll parent, ll all_cost){
        depth[source] = all_cost;
        items(e, tree[source]){
            if (e.to == parent) continue;
            dfs(e.to, source, all_cost + e.cost);
        }
    }

    ll n, k, a, b, c;

    in2(n, k);
    rep(i, n - 1){
        in3(a, b, c);
        a--; b--;
        tree[a].pb({b, c});
        tree[b].pb({a, c});
    }

    k--;
    dfs(k, -1, 0);

    #10. Visiting Subtree using recurrent function (ABC138D)

    gr tree[MAX_N];
    ll c[MAX_N];
    bool visited[MAX_N];

    void dfs(ll source, ll parent, ll val){
        visited[source] = true;
        c[source] += val;
        rep(i, tree[source].size()){
            rep(i, m){ll res = n % match[i].e1;}
            ll vertex = tree[source][i].to;
            if (vertex == parent) continue;
            dfs(vertex, source, c[source]);
        }
    }

    #11. bfs ABC146D, ABC007C
    1. first create a tree.
    2. start searching from a node.
    3. do some processes and push nodes connected with a given target node in BFS.
    4. repeat a series of procedure until queue is empty.

    queue<pl> q;

    void bfs(ll source, ll parents){
        ll n_edge = G[source].size();
        if (parents != -1) dist[source] = min(dist[source], dist[parents] + 1);
        if (visited[source]) return;
        visited[source] = true;

        rep(idx, n_edge){
            ll target = G[source][idx].to;
            if (target == parents) continue;
            q.push(mp(target, source)); 
        }
    }

    q.push(mp(sg.e1, -1));
    while(!q.empty()){
        pl source = q.front(); q.pop();
        bfs(source.e1, source.e2);
    }

    #12. grid to distance matrix (dx, dy)
    ll w, h;
    ll pos_to_idx(ll x, ll y){
        return y * w + x;
    }

    pl idx_to_pos(ll idx){
        return mp(idx % w, idx / w); 
    }

    int main(void){
        in2(h, w);
        rep(y, h){
            in1(s);
            rep(x, w){
                if (s[x] == '#') wall[x][y] = true;
                else wall[x][y] = false;
            }
        }

        rep(i1, h * w)rep(i2, h * w) dist[i1][i2] = INF * (i1 != i2);

        rep(x, w)rep(y, h){
            ll idx1 = pos_to_idx(x, y); ll idx2;
            if (wall[x][y]) continue;
            if (x != 0 && !wall[x - 1][y]){
                idx2 = pos_to_idx(x - 1, y);
                // if warshall floyd
                dist[idx1][idx2] = 1;
                // if dijkstra
                // graph[idx1].pb({idx2, 1});
            }
            if (x != w - 1 && !wall[x + 1][y]){
                idx2 = pos_to_idx(x + 1, y);
                dist[idx1][idx2] = 1;
                // graph[idx1].pb({idx2, 1});
            }
            if (y != 0 && !wall[x][y - 1]){
                idx2 = pos_to_idx(x, y - 1);
                dist[idx1][idx2] = 1;
                // graph[idx1].pb({idx2, 1});
            }
            if (y != h - 1 && !wall[x][y + 1]){
                idx2 = pos_to_idx(x, y + 1);
                dist[idx1][idx2] = 1;
                // graph[idx1].pb({idx2, 1});
            }
        }
    }


*/

/*
# the operators regarding bit
& (AND), | (OR), ^ (XOR)
- (REVERSE), >> (SMALLER SHIFT)
<< (BIGGER SHIFT)


     x1: 0000 0001 0010 0101 0110 0111 0111
     x2: xxxx 0001 0011 0100 0101 1000 0110
x1 & x2: 0000 0001 0010 0100 0100 0000 0110

      x: 1001 1010  1100 1011 1101  1111
x & - x: 0001 0010  0100 0001 0001  0001
    sum: 1010 1100 10000 1100 1100 10000

x << y is x * 2 ** y
x >> y is rep(i, y) x = x // 2 

Let S be a bit sequence and i be a non-negative integer
S & (1 << i) -> if true, i in S
S | (1 << i) -> S union {i}
S & -(1 << i) -> S - {i}
__builtin_popcount(S) -> the number of elements in S
S = 0 -> S is an empty set
S = (1 << n) - 1 -> S includes all the elements up to the n-th

#Conditional Operator
condition ? true : false;

#iterator
type declaration: auto
value reference: *itr
increment: itr++
decrement: itr--
substitution of value: *itr = smt
*/

const ll MAX_N = 200005;
bool okay = false;
ll answer = 0;
ll n, m;
ll a[2004], b[2004];
ll dp[2004][2004], s[2004][2004];

void solve(){
    rep(i, n) in1(a[i]);
    rep(i, m) in1(b[i]);
    rep(i, n + 1) rep(j, m + 1) s[i][j] = dp[i][j] = 0;

    dp[0][0] = 1, dp[1][0] = dp[0][1] = 0; answer = 0;
    answer += dp[0][0];
    For(i, 1, n + 1){
        For(j, 1, m + 1){
            s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + MOD;
            s[i][j] %= MOD;
            if (a[i - 1] == b[j - 1]){
                dp[i][j] = (s[i - 1][j - 1] + 1) % MOD;
                s[i][j] += dp[i][j] % MOD; s[i][j] %= MOD;
                answer += dp[i][j]; answer %= MOD;
            }
        }
    }

    prl(answer);

    // check negative MOD
    // check index flow
    // check overwrite of the input variables
}

int main(void){
    in2(n, m);
    // assert(n <= 100);
    solve();

    return 0;
}