#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp> // Common file
//#include <ext/pb_ds/seg_tree_policy.hpp> // Including seg_sum_order_statistics_node_update
#include <stdio.h>
#include <cassert>
using namespace std;
//using namespace __gnu_pbds;
typedef long long  lo;
typedef pair<lo,lo> ll;//pair
typedef vector<lo> vl;  //vector of long
typedef vector<ll > vll;   //vector of pair
typedef priority_queue<lo>p_q;
typedef vector< vl > vvl;  //vector of vectors
#define X first
#define Y second
#define mp(a,b) make_pair((a),(b))
#define REP(a,b) for(lo i=(a);i<(lo)b;i++)//no need to declare variable i
#define REPE(a,b,c,d) REP(a,b)for(lo j=(c);j<(lo)d;j++)//no need to declare vaiables i,j
#define REPV(a,b,c) for((a)=b;(a)<(c);(a)++)//a is the variable
#define IREP(a,b) for(lo i=(a);i>=(b);i--)
#define IREPV(a,b,c) for((a)=b;(a)>=(c);(a)--)
#define all(v) (v).begin(),(v).end()
#define TRV(a) for(auto it : a)
#define INF 200100
#define MOD 1000000007
#define M 1000000007
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
#define pb(a) push_back((a))
#define meme(a,b) memset(a, b, sizeof a)
#define BASE 1005LL
/*order statistic seg_sum
typedef
seg_sum<
  lo,
    null_type,
  less_equal<lo>,
  rb_seg_sum_tag,
  // This policy updates nodes' metadata for order statistics.
  seg_tree_order_statistics_node_update>
ordered_set;*/

/*#define gc getchar_unlocked
#define pc putchar_unlocked
inline void sprlo( lo a){
    lo i=0;
    char S[20];
    if(a==0)pc('0');
    if(a<0){
        pc('-');
        a*=-1;
    }
    while(a>0){
        S[i++]=a%10+'0';
        a=a/10;
    }
    --i;
    while(i>=0)
    pc(S[i--]);
    pc(' ');
}
inline void lprlo( lo a){
    lo i=0;
    char S[20];
    if(a==0)pc('0');
    while(a>0){
        S[i++]=a%10+'0';
        a=a/10;
    }
    --i;
    while(i>=0)
    pc(S[i--]);
    pc('\n');
}
inline lo uscan(){
    lo n=0;
    char c=gc();
    while(c<'0'||c>'9')c=gc();
    while(c<='9'&&c>='0'){
	    n=n*10+c-'0';
	    c=gc();
	}
    return n;
}*//*
map<lo,lo> F;
vl a(INF),seg_tree(4*INF),lazy(4*INF);
lo f(lo n) {
	if (F.count(n)) return F[n];
	lo k=n/2;
	if (n%2==0) { // n=2*k
		return F[n] = (f(k)*f(k) + f(k-1)*f(k-1)) % M;
	} else { // n=2*k+1
		return F[n] = (f(k)*f(k+1) + f(k-1)*f(k)) % M;
	}
}
void build(lo node,lo start , lo end){
	if(start == end){
		seg_tree[node] = f(a[node]);
	}
	else{
		lo mid = (start +end) / 2;
		build( 2 * node + 1 , start , mid);
		build(2*node + 2, mid+1 ,end);
		seg_tree[node] = seg_tree[node * 2 + 1] + seg_tree[node*2+2];
		return;
	}
}
void update(lo node, lo start, lo end, lo l, lo r, lo val){
    if(lazy[node] != 0){
        // This node needs to be updated
        seg_tree[node] += (end - start + 1) * lazy[node];    // Update it
        if(start != end){
            lazy[node*2+1] += lazy[node];                  // Mark child as lazy
            lazy[node*2+2] += lazy[node];                // Mark child as lazy
        }
        lazy[node] = 0;                                  // Reset it
    }
    if(start > end or start > r or end < l)return;
    if(start >= l and end <= r){
        // Segment is fully within range
        seg_tree[node] += (end - start + 1) * val;
        if(start != end){
            // Not leaf node
            lazy[node*2+1] += val;
            lazy[node*2+2] += val;
        }
        return;
    }
    lo mid = (start + end) / 2;
    update(node*2 + 1, start, mid, l, r, val);        // Updating left child
    update(node*2 + 2, mid + 1, end, l, r, val);   // Updating right child
    seg_tree[node] = seg_tree[node*2 +1] + seg_sum[node*2+2];        // Updating root with max value
}
lo queryRange(lo node, lo start, lo end, lo l, lo r){
    if(start > end or start > r or end < l)return 0;         // Out of range
    if(lazy[node] != 0){
        // This node needs to be updated
        seg_sum[node] += (end - start + 1) * lazy[node];            // Update it
        if(start != end){
            lazy[node*2+1] += lazy[node];         // Mark child as lazy
            lazy[node*2+2] += lazy[node];    // Mark child as lazy
        }
        lazy[node] = 0;                 // Reset it
    }
    if(start >= l and end <= r)return seg_sum[node];
    lo mid = (start + end) / 2;
    lo p1 = queryRange(node*2 + 1, start, mid, l, r);         // Query left child
    lo p2 = queryRange(node*2 + 2, mid + 1, end, l, r); // Query right child
    return (p1 + p2);
}*/

int main(){
    lo n,m,arr[26],j;
    meme(arr,0);
    string s;
    cin>>n>>m;
    REP(0,n){
        cin>>s;
        REPV(j,0,s.length())arr[s[j]-'a']++;
    }
    lo co1=0,co2=0,co4=0;
    //cout<<"2"<<endl;
    REP(0,26){
        while(arr[i]>=4){
            co4++;
            arr[i]-=4;
        }
        while(arr[i]>=2){
            co2++;
            arr[i]-=2;
        }
        if(arr[i]==1)co1++;
    }
    //cout<<"1"<<endl;
    if(n%2==0 && m%2==0){
        if(co4 >= (n/2)*(m/2))cout<<"Yes";
        else cout<<"No";
    }else if(n%2!=0 && m%2!=0){
        if(co4 >= (n/2)*(m/2)){
            co2 = co2 + (co4 - (n/2)*(m/2))*2;
            if(co2 >= (n/2 + m/2)){
                co1 = co1 + (co2 - (n/2+m/2))*2;
                if(co1 >= 1)cout<<"Yes";
                else cout<<"No";
            }else cout<<"No";
        }else cout<<"No";
    }else if(n%2!=0){
        if(co4>=(n/2)*(m/2)){
            co2 = co2 + (co4 - (n/2)*(m/2))*2;
            if(co2 >= (m/2))cout<<"Yes";
            else cout<<"No";
        }else cout<<"No";
    }else if(m%2!=0){
        if(co4>=(n/2)*(m/2)){
            co2 = co2 + (co4 - (n/2)*(m/2))*2;
            if(co2 >= (n/2))cout<<"Yes";
            else cout<<"No";
        }else cout<<"No";
    }
    return 0;
}


Measured memory_bytes: 256