// dfmt off
T lread(T=long)(){return readln.chomp.to!T;}T[] lreads(T=long)(long n){return iota(n).map!((_)=>lread!T).array;}
T[] aryread(T=long)(){return readln.split.to!(T[]);}void arywrite(T)(T a){a.map!text.join(' ').writeln;}
void scan(L...)(ref L A){auto l=readln.split;foreach(i,T;L){A[i]=l[i].to!T;}}alias sread=()=>readln.chomp();
void dprint(L...)(lazy L A){debug{auto l=new string[](L.length);static foreach(i,a;A)l[i]=a.text;arywrite(l);}}
static immutable MOD=10^^9+7;alias PQueue(T,alias l="b<a")=BinaryHeap!(Array!T,l);import std;
// dfmt on

void main()
{
    long H, W;
    scan(H, W);
    auto cnt = new long[](26);
    foreach (_; 0 .. H)
    {
        auto A = sread();
        foreach (a; A)
        {
            cnt[a - 'a']++;
        }
    }
    auto pool = () {
        if (H == 1)
            return [0, 1, (W - 1) / 2];
        if (W == 1)
            return [0, 1, (H - 1) / 2];
        if (H & 1 && W & 1)
            return [0, 1, (W - 1) / 2 + (H - 1) / 2, 0, ((W - 1) / 2) * ((H - 1) / 2)];
        if (H & 1)
            return [0, 0, W / 2, 0, (W / 2) * ((H - 1) / 2)];
        if (W & 1)
            return [0, 0, H / 2, 0, (H / 2) * ((W - 1) / 2)];
        return [0, 0, 0, 0, (W / 2) * (H / 2)];
    }();
    foreach_reverse (x; 0 .. pool.length)
    {
        // dprint(cast(char)(i + 'a'), cnt[i], pool);
        foreach (i; 0 .. cnt.length)
        {
            if (0 < pool[x] && x <= cnt[i])
            {
                while (0 < pool[x] && x <= cnt[i])
                {
                    cnt[i] -= x;
                    pool[x]--;
                }
            }
        }
        // dprint(cast(char)(i + 'a'), cnt[i], pool);
        if (pool[x] != 0)
        {
            writeln("No");
            return;
        }
    }
    writeln(pool.all!"a==0" ? "Yes" : "No");
}
