/*Remember me,
shall you deny,
death will reply*/

#include <iostream>
#include<vector>
#define pb push_back
#define f first
#define s second

using namespace std;

typedef long long int ll;

ll ncr(ll n,ll r)
{
    ll num=1;
    for(ll i=2;i<=n;i++)
        num*=i;
    ll den1=1,den2=1;
    for(ll i=2;i<=r;i++)
        den1*=i;
    for(ll i=2;i<=n-r;i++)
        den2*=i;
    return num/(den1*den2);
}

int main()
{
    //optimization tool
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);

    ll a[5]={0,1,14,36,24};
    string s;
    cin>>s;
    ll x=0,y=0;
    for(ll i=0;i<s.size();i++)
    {
        if(s[i]=='o')
           x++;
        if(s[i]=='?')
            y++;
    }
    if(x>4||(x==0&&y==0))
    {
        cout<<0<<endl;
        return 0;
    }
    //cout<<"x "<<x<<" "<<y<<endl;
    ll res=a[x];
   // cout<<res<<" res"<<endl;
    ll i=1;
    while(x+i<=4&&y>=i)
    {
        res+=ncr(y,i)*a[x+i];
        //cout<<"here "<<ncr(y,i)<<" "<<a[x+i]<<endl;
        i++;
    }
    cout<<res<<endl;
    return 0;
}

// give up
#include <bitset>
#include <iostream>
#include <iomanip>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>

// alias, using declaration
using llint = long long; using ldouble = long double;
template <class T = llint> using vector = std::vector<T>;
template <class T = llint> using deque = std::deque<T>;
template <class T = llint, class U = llint, class... V> using map = std::map<T, U, V...>;
template <class T = llint, class... U> using set = std::set<T, U...>;
template <class T = llint, class U = llint> using umap = std::unordered_map<T, U>;
template <class T = llint> using uset = std::unordered_set<T>;
template <class T = llint, class U = T> using pair = std::pair<T, U>;
template <class T = llint> using varray = std::valarray<T>;
template <class T = llint, class... U> using pqueue = std::priority_queue<T, U...>;
using std::bitset; using std::string; using std::tuple;

// constant
constexpr llint INF4 = 0x3FFFFFFF;
constexpr llint INF8 = 0x3FFFFFFFFFFFFFFF;
constexpr llint INVALID = 0x8000000000000000;

namespace io {
  // in
  template <class... T, size_t... S> auto in(std::index_sequence<S...>) {tuple<T...> t; (..., (std::cin >> std::get<S>(t))); return t;}
  template <class... T, size_t... S> auto in(std::index_sequence<S...>, size_t n) {tuple<vector<T>...> t{vector<T>(n)...}; for (size_t i = 0; i < n; i++) (..., (std::cin >> std::get<S>(t)[i])); return t;}
  template <size_t N, class T = llint, class... U, class... A> auto in(A... a) {static_assert(N >= 1); if constexpr (N > 1) return in<N - 1, T, T, U...>(a...); else return in<T, U...>(std::index_sequence_for<T, U...>(), a...);}
  // out
  template <bool F = true, class T, class... U> void out(const T& a, const U&... b) {(F ? std::cout : std::cerr) << a << (sizeof...(b) ? " " : "\n"); if constexpr (sizeof...(b)) out<F>(b...);}
  template <bool F = true, class T, class U = const char*> void out(const vector<T>& a, U d = " ") {for (auto&& b : a) (F ? std::cout : std::cerr) << b << (&b != &a.back() ? d : "\n");}
}

int main() {
  // input
  auto [N, M] = io::in<2>();
  auto [A, B] = io::in<2>(M);
  for (auto& i : A) i--;
  for (auto& i : B) i--;

  // solve
  vector<vector<>> graph(N);
  for (llint i = 0; i < M; i++) {
    graph[A[i]].emplace_back(B[i]);
  }
  auto dfs = [&graph](auto f, llint node, uset<>& visited) -> void {
    visited.emplace(node);
    for (auto next : graph[node]) {
      if (visited.count(next) > 0) continue;
      f(f, next, visited);
    }
  };
  llint sum = 0;
  for (llint i = 0; i < N; i++) {
    uset<> visited;
    dfs(dfs, i, visited);
    sum += visited.size();
  }

  // output
  auto result = sum;
  io::out(result);
}