#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define all(a) (a).begin(),(a).end()
#define endl "\n"
#define rep(i, a, b) for (auto (i) = (a); (i) < (b); (i)++)
#define rrep(i, a, b) for (auto (i) = (a); (i) > (b); (i)--)
#define UNIQUE(v) (v).erase(unique((v).begin(), (v).end()), (v).end());
#define BEGIN_SOLVER class Solver{public:
#define END_SOLVER };

#ifdef LOCAL_DEFINE
struct InitInput{
  InitInput() {
    FILE *stream1;
    stream1 = freopen("/Users/aim_cpo/CLionProjects/competitive/in.txt", "r", stdin);
    assert(stream1 != nullptr);
    cerr << "This problem is not interactive" << endl;
  }
}LOCAL_INPUT;
struct LOCAL_OUTPUT{
  LOCAL_OUTPUT() {
    FILE *stream2;
    const char *outputfile = "out.txt";
    stream2 = freopen(outputfile, "w", stdout);
    assert(stream2 != nullptr);
    cerr << "output [ " << outputfile << " ]" << endl;
  }
}/*LOCAL_OUTPUT*/;
#define show(x) cerr << #x << " = " << (x) << " (line " << __LINE__ << ")" << endl
#define showA(a, n) do{\
for(int _i_t_e_=0;_i_t_e_<(n);_i_t_e_++)\
cerr<<"("<<_i_t_e_<<" = "<<(a)[_i_t_e_]<<") ";\
cerr<<endl;}while(0)
#define showA2(a, n, m) do{\
for(int _i_t_e_=0;_i_t_e_<(n);_i_t_e_++){\
for(int _i_t_e_2=0;_i_t_e_2<(m);_i_t_e_2++){\
cerr<<"("<<_i_t_e_<<", "<<_i_t_e_2<<" = "<<(a)[_i_t_e_][_i_t_e_2]<<") ";\
}cerr<<endl;}cerr<<endl;}while(0)
#else
#define show(x)
#define showA(a, n)
#define showA2(a, n, m)
#endif

struct InitAim{
  InitAim() {
    ios::sync_with_stdio(false);cin.tie(nullptr);
    cout.precision(12);cout<<fixed;
#ifdef LOCAL_DEFINE
    cerr << "This problem is not interactive" << endl;
#endif
  }
}aim_cpo;

typedef long long ll;

constexpr const int INT_INF=0x3f3f3f3f; //1061109567
constexpr const ll LL_INF=0x3f3f3f3f3f3f3f3f; //4557430888798830399

template <typename T> bool chmin(T &a, T b){return a>b?(a=b,true):false;}
template <typename T> bool chmax(T &a, T b){return a<b?(a=b,true):false;}
template <typename T> void ln(T i, T n){cout<<(i==n-1?"\n":" ");}
template<typename T, typename S>
ostream &operator<<(ostream &out, const pair<T, S> &pair1) {
  out << '(' << pair1.fi << ", " << pair1.se << ')';
  return out;
}
template<typename T>
ostream &operator<<(ostream &out, const vector<T> &vector1) {
  out << '[';
  for (unsigned int i = 0; i < vector1.size(); i++) {
    out << vector1[i];
    if (i == vector1.size() - 1)out << "]"; else out << ", ";
  }
  return out;
}

// INT
#define GCD(a, b) __gcd(a, b)
template <typename T> T LCM(T a, T b) {return a / GCD(a, b) * b;}
template <typename T> T EXTGCD(T a, T b, T& x, T& y) {
  T d = a;
  if (b != 0) {d=EXTGCD(b,a%b,y,x);y-=(a/b)*x;}
  else x=1,y=0;
  return d;
}
template <typename T> bool is_prime(T a) {
  for(int i=2;i*i<=a;i++)if(a%i==0)return true;
  return false;
}
template <typename T, typename S> T Pow(T a, S b) {
  T res = 1, now = a;
  while(b){if(b&1)res*=now;b>>=1;now*=now;}return res;
}

// MOD
ll MOD = 1000000000L + 7L;
#define add(a, b) (((a) % MOD) + ((b) % MOD)) % MOD
#define mul(a, b) (((a) % MOD) * ((b) % MOD)) % MOD
#define sub(a, b) (((a) % MOD) + MOD - ((b) % MOD)) % MOD
template <typename T, typename S> T ModPow(T a, S b) {
  assert(b >= 0);
  T res = 1, now = sub(a, 0);
  while(b){if(b&1)res=mul(res,now);b>>=1;now=mul(now,now);}return res;
}
template <typename T> T mod_inverse(T a, T mod, bool prime){ // if mod is prime, "prime" is true.
  if(prime)return ModPow(a, mod - 2);
  else{T x,y;EXTGCD(a,mod,x,y);return (mod+x%mod)%mod;}
}
template <typename T> T EulerTotient(T a) {
  vector <pair <int, int> > v;
  for (T i = 2; i * i <= a; i++) {
    int cnt = 0;
    while (a % i == 0) {cnt++; a /= i;}
    if (cnt != 0) v.emplace_back(i, cnt);
  }
  if (a != 1) v.emplace_back(a, 1);
  //showV(v, (int) v.size());
  T res = 1;
  for (int i = 0; i < (int) v.size(); i++) {
    if (v[i].se == 1) {
      //res *= v[i].fi - 1;
      res = mul(res, v[i].fi - 1);
    } else {
      //res *= Pow(v[i].fi, v[i].se) - Pow(v[i].fi, v[i].se - 1);
      res = mul(res, sub(ModPow(v[i].fi, v[i].se), ModPow(v[i].fi, v[i].se - 1)));
    }
  }
  return res;
}
#define divide(a, b) mul(((a) % MOD), (mod_inverse((b), MOD, true))) % MOD
ll comb(ll a, ll b) {
  chmin(b, a - b);
  ll res = 1LL, now = a;
  for (ll i = 1; i <= b; i++) {
    res = mul(res, now); //res *= now;
    res = divide(res, i); // res /= i;
    now--;
  }
  return res;
}
// 735134400 約数が1344個ある高度合成数(<= 1e9)
// 897612484786617600 約数が103680個ある高度合成数(<= 1e18)
// 苦手分野 重複順列
// LLの数値をつかう時は最後にLLをつける癖をつけよう

BEGIN_SOLVER

///////////////////////////////////////////////////////////////////////////////////
// SOLVER
///////////////////////////////////////////////////////////////////////////////////

Solver(){
  input();
  solve();
}

///////////////////////////////////////////////////////////////////////////////////
// VARIABLE
///////////////////////////////////////////////////////////////////////////////////

int n, q;
string s;
char t[200001], d[200001];

///////////////////////////////////////////////////////////////////////////////////
// INPUT
///////////////////////////////////////////////////////////////////////////////////

void input(){
  cin >> n >> q;
  cin >> s;
  rep(i, 0, q) cin >> t[i] >> d[i];
}

///////////////////////////////////////////////////////////////////////////////////
// SOLVE
///////////////////////////////////////////////////////////////////////////////////

int BinarySearch(string &s) {
  int ok = -1, ng = n + 1;
  while (ng - ok > 1) {
    int mid = (ng + ok) / 2;
    auto check = [&](int mid) {
      if (mid == -1) return true;
      int now = mid;
      char nowc = s[mid];
      rep(i, 0, q) {
        if (nowc != t[i]) continue;
        if (d[i] == 'L') {
          now--;
        } else {
          now++;
        }
        if (now < 0) return false;
        if (now > n - 1) return true;
        nowc = s[now];
      }
      if (now >= 0) return true;
    };
    if (check(mid)) ng = mid;
    else ok = mid;
  }
  return ok;
}

void solve(){
  int ans = n;
  ans -= BinarySearch(s) + 1;
  reverse(all(s));
  rep(i, 0, q) {
    if (d[i] == 'L') d[i] = 'R';
    else d[i] = 'L';
  }
  ans -= BinarySearch(s) + 1;
  cout << ans << endl;
}

///////////////////////////////////////////////////////////////////////////////////
// OUTPUT
///////////////////////////////////////////////////////////////////////////////////

void output(){
}

///////////////////////////////////////////////////////////////////////////////////
// NOTE
///////////////////////////////////////////////////////////////////////////////////

// 二分探索するんやろなー(そっ閉じ)...
// なんでそっ閉じしたんや俺...方針合っとるがな...
// 気をつけることは、ある区間が落ちるか落ちないかの判定は区間の端にのみ注目することで可能だということ
// 区間全てに注目したくなるが、区間の端だけで良い.

///////////////////////////////////////////////////////////////////////////////////
// TEMPLATE(data structure)
///////////////////////////////////////////////////////////////////////////////////

class UnionFind {
public:
  explicit UnionFind(int _n) : n(_n) {
    par.resize(_n);
    rank.resize(_n);
    sizes.resize(_n);
    for (int i = 0; i < _n; i++) {
      par[i] = i;
      rank[i] = 0;
      sizes[i] = 1;
    }
  }
  int find(int a) {
    if (par[a] == a) return a;
    return par[a] = find(par[a]);
  }
  bool same(int a, int b) {
    return find(a) == find(b);
  }
  void unite(int a, int b) {
    link(find(a), find(b));
  }
  int size(int a) {
    return sizes[find(a)];
  }
  void view() {
    for (int i = 0; i < n; i++) {
      cout << " par" << "[" << i << "]=" << par[i] << ((i == n - 1) ? "\n" : ",");
    }
    for (int i = 0; i < n; i++) {
      cout << "size" << "[" << i << "]=" << sizes[i] << ((i == n - 1) ? "\n" : ",");
    }
    cout << endl;
  }
private:
  void link(int a, int b) {
    if (same(a, b)) return;
    if (rank[a] > rank[b]) {
      par[b] = a;
      sizes[a] += sizes[b];
      sizes[b] = 0;
    } else {
      par[a] = b;
      if (rank[a] == rank[b]) rank[b]++;
      sizes[b] += sizes[a];
      sizes[a] = 0;
    }
  }
  int n;
  vector<int> par;
  vector<int> rank;
  vector<int> sizes;
};

template <typename T>
class IntervalTree {
  using F = function<T(T, T)>;
public:
  IntervalTree(int n, const F func, const T init) : func(func), init(init) {
    size = 1;
    while ((int)size < n) size <<= 1;
    table.assign(2 * size, init);
  }
  void set(int k, T x) {
    table[size + k] = x;
  }
  void build() {
    for (int i = size - 1; i >= 0; --i) {
      table[i] = func(table[i * 2], table[i * 2 + 1]);
    }
  }
  void update(int k, const T &x) {
    k += size;
    table[k] = x;
    while (k >>= 1) {
      table[k] = func(table[k * 2], table[k * 2 + 1]);
    }
  }
  T query(int a, int b) {
    T L = init, R = init;
    for (a += size, b += size; a < b; a >>= 1, b >>= 1) {
      if (a & 1) L = func(L, table[a++]);
      if (b & 1) R = func(table[--b], R);
    }
    return func(L, R);
  }
  T operator[](const int k) const {
    return table[k + size];
  }
private:
  unsigned int size;
  vector<T> table;
  const F func;
  const T init;
};

template <typename T, typename S = T>
class LazyIntervalTree {
  using F = function<T(T, T)>;
  using G = function<T(T, S, int)>;
  using H = function<S(S, S)>;
public:
  LazyIntervalTree(int n, const F f, const G g, const H h, const T &init, const S OM)
    : f(f), g(g), h(h), init(init), OM(OM) {
    size = 1;
    while (size < n) size <<= 1;
    data.assign(2 * size, init);
    lazy.assign(2 * size, OM);
  }
  void set(int k, const T &x) {
    data[k + size] = x;
  }
  void build() {
    for (int i = size - 1; i > 0; i--) {
      data[i] = f(data[2 * i], data[2 * i + 1]);
    }
  }
  void propagate(int k, int len) {
    if (lazy[k] != OM) {
      if (k < size) {
        lazy[2 * k] = h(lazy[2 * k], lazy[k]);
        lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
      }
      data[k] = g(data[k], lazy[k], len);
      lazy[k] = OM;
    }
  }
  T update(int a, int b, const S &x, int k, int l, int r) {
    propagate(k, r - l);
    if (r <= a || b <= l) {
      return data[k];
    } else if (a <= l && r <= b) {
      lazy[k] = h(lazy[k], x);
      propagate(k, r - l);
      return data[k];
    } else {
      return data[k] = f(update(a, b, x, 2 * k, l, (l + r) >> 1),
                         update(a, b, x, 2 * k + 1, (l + r) >> 1, r));
    }
  }
  T update(int a, int b, const S &x) {
    return update(a, b, x, 1, 0, size);
  }
  T query(int a, int b, int k, int l, int r) {
    propagate(k, r - l);
    if (r <= a || b <= l) {
      return init;
    } else if (a <= l && r <= b) {
      return data[k];
    } else {
      return f(query(a, b, 2 * k, l, (l + r) >> 1),
               query(a, b, 2 * k + 1, (l + r) >> 1, r));
    }
  }
  T query(int a, int b) {
    return query(a, b, 1, 0, size);
  }
  T operator[](const int &k) {
    return query(k, k + 1);
  }
private:
  int size;
  vector <T> data;
  vector <S> lazy;
  const F f;
  const G g;
  const H h;
  const T init;
  const S OM;
};

template <typename T>
class BIT {
public:
  BIT(int size) {
    BITTable.assign(++size, 0);
  }
  T sum(int k) {
    T res = 0;
    for (++k; k > 0; k -= k & -k) {
      res += BITTable[k];
    }
    return res;
  }
  T sum(int l, int r) { // [l, r]
    if (l == 0) return sum(r);
    return sum(r) - sum(l - 1);
  }
  void update(int k, T x) { // b[k] += x;
    for (++k; k < (int)BITTable.size(); k += k & -k) BITTable[k] += x;
  }
private:
  vector<T> BITTable;
};

END_SOLVER

///////////////////////////////////////////////////////////////////////////////////
// MAIN
///////////////////////////////////////////////////////////////////////////////////

int main() {
  Solver ans;
#ifdef LOCAL_DEFINE
  cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s." << endl;
  show(MOD);
#endif
  return 0;
}

Measured memory_bytes: 976