//package ecr012;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class F3 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	public static int[] sieveEratosthenes(int n) {
		if (n <= 32) {
			int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
			for (int i = 0; i < primes.length; i++) {
				if (n < primes[i]) {
					return Arrays.copyOf(primes, i);
				}
			}
			return primes;
		}

		int u = n + 32;
		double lu = Math.log(u);
		int[] ret = new int[(int) (u / lu + u / lu / lu * 1.5)];
		ret[0] = 2;
		int pos = 1;

		int[] isnp = new int[(n + 1) / 32 / 2 + 1];
		int sup = (n + 1) / 32 / 2 + 1;

		int[] tprimes = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
		for (int tp : tprimes) {
			ret[pos++] = tp;
			int[] ptn = new int[tp];
			for (int i = (tp - 3) / 2; i < tp << 5; i += tp)
				ptn[i >> 5] |= 1 << (i & 31);
			for (int j = 0; j < sup; j += tp) {
				for (int i = 0; i < tp && i + j < sup; i++) {
					isnp[j + i] |= ptn[i];
				}
			}
		}

		// 3,5,7
		// 2x+3=n
		int[] magic = { 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, 7, 12, 21, 17,
				9, 6, 16, 5, 15, 14 };
		int h = n / 2;
		for (int i = 0; i < sup; i++) {
			for (int j = ~isnp[i]; j != 0; j &= j - 1) {
				int pp = i << 5 | magic[(j & -j) * 0x076be629 >>> 27];
				int p = 2 * pp + 3;
				if (p > n)
					break;
				ret[pos++] = p;
				if ((long) p * p > n)
					continue;
				for (int q = (p * p - 3) / 2; q <= h; q += p)
					isnp[q >> 5] |= 1 << q;
			}
		}

		return Arrays.copyOf(ret, pos);
	}

	int[] primes = sieveEratosthenes(400000);

	void solve()
	{
		long n = nl();
		long ans = 0;
		MeisselLehmer2 ml = new MeisselLehmer2(n/2);
		for(int i = 0;i < primes.length;i++) {
			long plus = ml.pi(n/primes[i]) - (i+1);
			if(plus <= 0)break;
			ans += plus;
		}

		for(int p : primes) {
			if((long)p*p*p <= n) {
				ans++;
			}else {
				break;
			}
		}
		out.println(ans);
	}

	public static class MeisselLehmer2 {
		int[] primes;
//		int[] cump;
		int[] xcums;
		long[] isp;

		int cachelimit;
//		Map<Long, Long> picache;
//		Map<Long, Long> phicache;
		LongHashCounterL picache;
		LongHashCounterL phicache;
		boolean cachePhi = true;

		int[][] cumps;
//		int[] FP = {2,3,5,7,11,13,17};
		int[] FP = {2,3,5,7,11,13,17,19};
		int M = FP.length;

		int B = 100;
		// 10^14 -> 200
		// 10^14/8 -> 100~200

		public MeisselLehmer2(long n)
		{
			assert n >= 4;
//			picache = new HashMap<>();
//			phicache = new HashMap<>();
			picache = new LongHashCounterL();
			phicache = new LongHashCounterL();

			int s = (int)Math.sqrt(n)*B; // not overflow!
			cachelimit = s;
			this.primes = sieveEratosthenes(s);
			xcums = new int[(s>>>6)+1];
			isp = new long[(s>>>6)+1];
			for(int p : primes)isp[p>>>6] |= 1L<<p;
			for(int i = 0;i < xcums.length-1;i++)xcums[i+1] = xcums[i] + Long.bitCount(isp[i]);

			cumps = new int[M][];
			boolean[] b = {true};
			int len = 1;
			for(int i = 0;i < M;i++){
				len *= FP[i];
				boolean[] c = new boolean[len];
				for(int j = 0;j < FP[i];j++){
					System.arraycopy(b, 0, c, j*b.length, b.length);
				}
				for(int k = 0;k < len;k+=FP[i])c[k] = false;
				cumps[i] = new int[len+1];
				for(int j = 0;j < len;j++)cumps[i][j+1] = cumps[i][j] + (c[j] ? 1 : 0);
				FP[i] = len;
				b = c;
			}
		}

		private long sqrt(long n)
		{
			long i = Math.max(0, (long)Math.sqrt(n)-2);
			while(i*i <= n)i++;
			return i-1;
		}

		private long cbrt(long n)
		{
			long i = Math.max(0, (long)Math.cbrt(n)-2);
			while(i*i*i <= n)i++;
			return i-1;
		}

		public long pi(long x)
		{
			if(x <= cachelimit){
				int ix = (int)x;
				return xcums[ix>>>6] + Long.bitCount(isp[ix>>>6]<<~ix);
//				return cump[(int)x];
			}
			if(picache.containsKey(x))return picache.get(x);

			int A = (int)pi(sqrt(sqrt(x)));
			long ret = A + phi(x, A) - P2(x, A) - P3(x, A) - 1;
			picache.put(x, ret);
			return ret;
		}

		private long phi(long x, int A)
		{
			if(A > 0 && A-1 < M){
				return cumps[A-1][FP[A-1]] * (x/FP[A-1]) + cumps[A-1][(int)(x%FP[A-1]+1)];
			}
			if(A > 0 && x <= (long)primes[A-1]*primes[A-1]){
				return pi(x) - A + 1;
			}
			long code = x<<13|A;
			if(phicache.containsKey(code))return phicache.get(code);

			long ret = x;
			for(int i = A-1;i >= 0;i--)ret -= phi(x/primes[i], i);

			if(cachePhi)phicache.put(code, ret);
			return ret;
		}

		private long P2(long x, int A)
		{
			int B = (int)pi(sqrt(x));
			long ret = 0;
			for(int i = A;i < B;i++){
				ret += pi(x/primes[i]);
			}
			ret -= (long)(B-A)*(B+A-1)/2;
			return ret;
		}

		private long P3(long x, int A)
		{
			int C = (int)pi(cbrt(x));
			long ret = 0;
			for(int i = A;i < C;i++){
				long xi = x/primes[i];
				int B = (int)pi(sqrt(xi));
				for(int j = i;j < B;j++){
					ret += pi(xi/primes[j]) - j;
				}
			}
			return ret;
		}

		public static int[] sieveEratosthenes(int n) {
			if (n <= 32) {
				int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
				for (int i = 0; i < primes.length; i++) {
					if (n < primes[i]) {
						return Arrays.copyOf(primes, i);
					}
				}
				return primes;
			}

			int u = n + 32;
			double lu = Math.log(u);
			int[] ret = new int[(int) (u / lu + u / lu / lu * 1.5)];
			ret[0] = 2;
			int pos = 1;

			int[] isnp = new int[(n + 1) / 32 / 2 + 1];
			int sup = (n + 1) / 32 / 2 + 1;

			int[] tprimes = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
			for (int tp : tprimes) {
				ret[pos++] = tp;
				int[] ptn = new int[tp];
				for (int i = (tp - 3) / 2; i < tp << 5; i += tp)
					ptn[i >> 5] |= 1 << (i & 31);
				for (int j = 0; j < sup; j += tp) {
					for (int i = 0; i < tp && i + j < sup; i++) {
						isnp[j + i] |= ptn[i];
					}
				}
			}

			// 3,5,7
			// 2x+3=n
			int[] magic = { 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, 7, 12, 21, 17,
					9, 6, 16, 5, 15, 14 };
			int h = n / 2;
			for (int i = 0; i < sup; i++) {
				for (int j = ~isnp[i]; j != 0; j &= j - 1) {
					int pp = i << 5 | magic[(j & -j) * 0x076be629 >>> 27];
					int p = 2 * pp + 3;
					if (p > n)
						break;
					ret[pos++] = p;
					if ((long) p * p > n)
						continue;
					for (int q = (p * p - 3) / 2; q <= h; q += p)
						isnp[q >> 5] |= 1 << q;
				}
			}

			return Arrays.copyOf(ret, pos);
		}

		private static class LongHashCounterL {
			public long[] keys;
			public long[] allocated;
			private int scale = 1<<2;
			private int rscale = 1<<1;
			private int mask = scale-1;
			public int size = 0;

			public LongHashCounterL(){
				allocated = new long[scale];
				Arrays.fill(allocated, NG);
				keys = new long[scale];
			}

			// if value is NG, entry is removed. (e.g. 0)
			private static final int NG = 0;

			public boolean containsKey(long x)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos])return true;
					pos = pos+1&mask;
				}
				return false;
			}

			public long get(long x)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos])return allocated[pos];
					pos = pos+1&mask;
				}
				return NG;
			}

			public long put(long x, long v)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos]){
						long oldval = allocated[pos];
						allocated[pos] = v;
						return oldval;
					}
					pos = pos+1&mask;
				}
				if(size == rscale){
					resizeAndPut(x, v);
				}else{
					keys[pos] = x;
					allocated[pos] = v;
				}
				size++;
				return 0;
			}

			public long inc(long x, long v)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos]){
						allocated[pos] += v;
						return allocated[pos];
					}
					pos = pos+1&mask;
				}
				if(size == rscale){
					resizeAndPut(x, v);
				}else{
					keys[pos] = x;
					allocated[pos] = v;
				}
				size++;
				return v;
			}

			public boolean remove(long x)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos]){
						size--;
						// take last and fill rmpos
						int last = pos;
						pos = pos+1&mask;
						while(allocated[pos] != NG){
							int lh = h(keys[pos])&mask;
							// lh <= last < pos
							if(
									lh <= last && last < pos ||
									pos < lh && lh <= last ||
									last < pos && pos < lh
									){
								keys[last] = keys[pos];
								allocated[last] = allocated[pos];
								last = pos;
							}
							pos = pos+1&mask;
						}
						keys[last] = 0;
						allocated[last] = NG;

						return true;
					}
					pos = pos+1&mask;
				}
				return false;
			}

			private void resizeAndPut(long x, long v)
			{
				int nscale = scale<<1;
				int nrscale = rscale<<1;
				int nmask = nscale-1;
				long[] nallocated = new long[nscale];
				Arrays.fill(nallocated, NG);
				long[] nkeys = new long[nscale];
				for(int i = next(0);i < scale;i = next(i+1)){
					long y = keys[i];
					int pos = h(y)&nmask;
					while(nallocated[pos] != NG)pos = pos+1&nmask;
					nkeys[pos] = y;
					nallocated[pos] = allocated[i];
				}
				{
					int pos = h(x)&nmask;
					while(nallocated[pos] != NG)pos = pos+1&nmask;
					nkeys[pos] = x;
					nallocated[pos] = v;
				}
				allocated = nallocated;
				keys = nkeys;
				scale = nscale;
				rscale = nrscale;
				mask = nmask;
			}

			public int next(int itr)
			{
				while(itr < scale && allocated[itr] == NG)itr++;
				return itr;
			}

			private int h(long x)
			{
				x ^= x>>>33;
				x *= 0xff51afd7ed558ccdL;
				x ^= x>>>33;
				x *= 0xc4ceb9fe1a85ec53L;
				x ^= x>>>33;
				return (int)x;
			}

			@Override
			public String toString()
			{
				StringBuilder sb = new StringBuilder();
				for(int i = next(0);i < scale;i = next(i+1)){
					sb.append(",");
					sb.append(keys[i] + ":" + allocated[i]);
				}
				return sb.length() == 0 ? "" : sb.substring(1);
			}
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new F3().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package ecr012;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class F3 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	public static int[] sieveEratosthenes(int n) {
		if (n <= 32) {
			int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
			for (int i = 0; i < primes.length; i++) {
				if (n < primes[i]) {
					return Arrays.copyOf(primes, i);
				}
			}
			return primes;
		}

		int u = n + 32;
		double lu = Math.log(u);
		int[] ret = new int[(int) (u / lu + u / lu / lu * 1.5)];
		ret[0] = 2;
		int pos = 1;

		int[] isnp = new int[(n + 1) / 32 / 2 + 1];
		int sup = (n + 1) / 32 / 2 + 1;

		int[] tprimes = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
		for (int tp : tprimes) {
			ret[pos++] = tp;
			int[] ptn = new int[tp];
			for (int i = (tp - 3) / 2; i < tp << 5; i += tp)
				ptn[i >> 5] |= 1 << (i & 31);
			for (int j = 0; j < sup; j += tp) {
				for (int i = 0; i < tp && i + j < sup; i++) {
					isnp[j + i] |= ptn[i];
				}
			}
		}

		// 3,5,7
		// 2x+3=n
		int[] magic = { 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, 7, 12, 21, 17,
				9, 6, 16, 5, 15, 14 };
		int h = n / 2;
		for (int i = 0; i < sup; i++) {
			for (int j = ~isnp[i]; j != 0; j &= j - 1) {
				int pp = i << 5 | magic[(j & -j) * 0x076be629 >>> 27];
				int p = 2 * pp + 3;
				if (p > n)
					break;
				ret[pos++] = p;
				if ((long) p * p > n)
					continue;
				for (int q = (p * p - 3) / 2; q <= h; q += p)
					isnp[q >> 5] |= 1 << q;
			}
		}

		return Arrays.copyOf(ret, pos);
	}

	int[] primes = sieveEratosthenes(400000);

	void solve()
	{
		long n = nl();
		long ans = 0;
		if(n <= 10) {
			if(n >= 6)ans++;
			if(n >= 8)ans++;
			if(n >= 10)ans++;
			out.println(ans);
			return;
		}

		MeisselLehmer2 ml = new MeisselLehmer2(n/2);
		for(int i = 0;i < primes.length;i++) {
			long plus = ml.pi(n/primes[i]) - (i+1);
			if(plus <= 0)break;
			ans += plus;
		}

		for(int p : primes) {
			if((long)p*p*p <= n) {
				ans++;
			}else {
				break;
			}
		}
		out.println(ans);
	}

	public static class MeisselLehmer2 {
		int[] primes;
//		int[] cump;
		int[] xcums;
		long[] isp;

		int cachelimit;
//		Map<Long, Long> picache;
//		Map<Long, Long> phicache;
		LongHashCounterL picache;
		LongHashCounterL phicache;
		boolean cachePhi = false;

		int[][] cumps;
//		int[] FP = {2,3,5,7,11,13,17};
		int[] FP = {2,3,5,7,11,13,17,19};
		int M = FP.length;

		int B = 100;
		// 10^14 -> 200
		// 10^14/8 -> 100~200

		public MeisselLehmer2(long n)
		{
			assert n >= 4;
//			picache = new HashMap<>();
//			phicache = new HashMap<>();
			picache = new LongHashCounterL();
			phicache = new LongHashCounterL();

			int s = (int)Math.sqrt(n)*B; // not overflow!
			cachelimit = s;
			this.primes = sieveEratosthenes(s);
			xcums = new int[(s>>>6)+1];
			isp = new long[(s>>>6)+1];
			for(int p : primes)isp[p>>>6] |= 1L<<p;
			for(int i = 0;i < xcums.length-1;i++)xcums[i+1] = xcums[i] + Long.bitCount(isp[i]);

			cumps = new int[M][];
			boolean[] b = {true};
			int len = 1;
			for(int i = 0;i < M;i++){
				len *= FP[i];
				boolean[] c = new boolean[len];
				for(int j = 0;j < FP[i];j++){
					System.arraycopy(b, 0, c, j*b.length, b.length);
				}
				for(int k = 0;k < len;k+=FP[i])c[k] = false;
				cumps[i] = new int[len+1];
				for(int j = 0;j < len;j++)cumps[i][j+1] = cumps[i][j] + (c[j] ? 1 : 0);
				FP[i] = len;
				b = c;
			}
		}

		private long sqrt(long n)
		{
			long i = Math.max(0, (long)Math.sqrt(n)-2);
			while(i*i <= n)i++;
			return i-1;
		}

		private long cbrt(long n)
		{
			long i = Math.max(0, (long)Math.cbrt(n)-2);
			while(i*i*i <= n)i++;
			return i-1;
		}

		public long pi(long x)
		{
			if(x <= cachelimit){
				int ix = (int)x;
				return xcums[ix>>>6] + Long.bitCount(isp[ix>>>6]<<~ix);
//				return cump[(int)x];
			}
			if(picache.containsKey(x))return picache.get(x);

			int A = (int)pi(sqrt(sqrt(x)));
			long ret = A + phi(x, A) - P2(x, A) - P3(x, A) - 1;
			picache.put(x, ret);
			return ret;
		}

		private long phi(long x, int A)
		{
			if(A > 0 && A-1 < M){
				return cumps[A-1][FP[A-1]] * (x/FP[A-1]) + cumps[A-1][(int)(x%FP[A-1]+1)];
			}
			if(A > 0 && x <= (long)primes[A-1]*primes[A-1]){
				return pi(x) - A + 1;
			}
//			long code = x<<13|A;
//			if(phicache.containsKey(code))return phicache.get(code);

			long ret = x;
			for(int i = A-1;i >= 0;i--)ret -= phi(x/primes[i], i);

//			if(cachePhi)phicache.put(code, ret);
			return ret;
		}

		private long P2(long x, int A)
		{
			int B = (int)pi(sqrt(x));
			long ret = 0;
			for(int i = A;i < B;i++){
				ret += pi(x/primes[i]);
			}
			ret -= (long)(B-A)*(B+A-1)/2;
			return ret;
		}

		private long P3(long x, int A)
		{
			int C = (int)pi(cbrt(x));
			long ret = 0;
			for(int i = A;i < C;i++){
				long xi = x/primes[i];
				int B = (int)pi(sqrt(xi));
				for(int j = i;j < B;j++){
					ret += pi(xi/primes[j]) - j;
				}
			}
			return ret;
		}

		public static int[] sieveEratosthenes(int n) {
			if (n <= 32) {
				int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
				for (int i = 0; i < primes.length; i++) {
					if (n < primes[i]) {
						return Arrays.copyOf(primes, i);
					}
				}
				return primes;
			}

			int u = n + 32;
			double lu = Math.log(u);
			int[] ret = new int[(int) (u / lu + u / lu / lu * 1.5)];
			ret[0] = 2;
			int pos = 1;

			int[] isnp = new int[(n + 1) / 32 / 2 + 1];
			int sup = (n + 1) / 32 / 2 + 1;

			int[] tprimes = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
			for (int tp : tprimes) {
				ret[pos++] = tp;
				int[] ptn = new int[tp];
				for (int i = (tp - 3) / 2; i < tp << 5; i += tp)
					ptn[i >> 5] |= 1 << (i & 31);
				for (int j = 0; j < sup; j += tp) {
					for (int i = 0; i < tp && i + j < sup; i++) {
						isnp[j + i] |= ptn[i];
					}
				}
			}

			// 3,5,7
			// 2x+3=n
			int[] magic = { 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, 7, 12, 21, 17,
					9, 6, 16, 5, 15, 14 };
			int h = n / 2;
			for (int i = 0; i < sup; i++) {
				for (int j = ~isnp[i]; j != 0; j &= j - 1) {
					int pp = i << 5 | magic[(j & -j) * 0x076be629 >>> 27];
					int p = 2 * pp + 3;
					if (p > n)
						break;
					ret[pos++] = p;
					if ((long) p * p > n)
						continue;
					for (int q = (p * p - 3) / 2; q <= h; q += p)
						isnp[q >> 5] |= 1 << q;
				}
			}

			return Arrays.copyOf(ret, pos);
		}

		private static class LongHashCounterL {
			public long[] keys;
			public long[] allocated;
			private int scale = 1<<2;
			private int rscale = 1<<1;
			private int mask = scale-1;
			public int size = 0;

			public LongHashCounterL(){
				allocated = new long[scale];
				Arrays.fill(allocated, NG);
				keys = new long[scale];
			}

			// if value is NG, entry is removed. (e.g. 0)
			private static final int NG = 0;

			public boolean containsKey(long x)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos])return true;
					pos = pos+1&mask;
				}
				return false;
			}

			public long get(long x)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos])return allocated[pos];
					pos = pos+1&mask;
				}
				return NG;
			}

			public long put(long x, long v)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos]){
						long oldval = allocated[pos];
						allocated[pos] = v;
						return oldval;
					}
					pos = pos+1&mask;
				}
				if(size == rscale){
					resizeAndPut(x, v);
				}else{
					keys[pos] = x;
					allocated[pos] = v;
				}
				size++;
				return 0;
			}

			public long inc(long x, long v)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos]){
						allocated[pos] += v;
						return allocated[pos];
					}
					pos = pos+1&mask;
				}
				if(size == rscale){
					resizeAndPut(x, v);
				}else{
					keys[pos] = x;
					allocated[pos] = v;
				}
				size++;
				return v;
			}

			public boolean remove(long x)
			{
				int pos = h(x)&mask;
				while(allocated[pos] != NG){
					if(x == keys[pos]){
						size--;
						// take last and fill rmpos
						int last = pos;
						pos = pos+1&mask;
						while(allocated[pos] != NG){
							int lh = h(keys[pos])&mask;
							// lh <= last < pos
							if(
									lh <= last && last < pos ||
									pos < lh && lh <= last ||
									last < pos && pos < lh
									){
								keys[last] = keys[pos];
								allocated[last] = allocated[pos];
								last = pos;
							}
							pos = pos+1&mask;
						}
						keys[last] = 0;
						allocated[last] = NG;

						return true;
					}
					pos = pos+1&mask;
				}
				return false;
			}

			private void resizeAndPut(long x, long v)
			{
				int nscale = scale<<1;
				int nrscale = rscale<<1;
				int nmask = nscale-1;
				long[] nallocated = new long[nscale];
				Arrays.fill(nallocated, NG);
				long[] nkeys = new long[nscale];
				for(int i = next(0);i < scale;i = next(i+1)){
					long y = keys[i];
					int pos = h(y)&nmask;
					while(nallocated[pos] != NG)pos = pos+1&nmask;
					nkeys[pos] = y;
					nallocated[pos] = allocated[i];
				}
				{
					int pos = h(x)&nmask;
					while(nallocated[pos] != NG)pos = pos+1&nmask;
					nkeys[pos] = x;
					nallocated[pos] = v;
				}
				allocated = nallocated;
				keys = nkeys;
				scale = nscale;
				rscale = nrscale;
				mask = nmask;
			}

			public int next(int itr)
			{
				while(itr < scale && allocated[itr] == NG)itr++;
				return itr;
			}

			private int h(long x)
			{
				x ^= x>>>33;
				x *= 0xff51afd7ed558ccdL;
				x ^= x>>>33;
				x *= 0xc4ceb9fe1a85ec53L;
				x ^= x>>>33;
				return (int)x;
			}

			@Override
			public String toString()
			{
				StringBuilder sb = new StringBuilder();
				for(int i = next(0);i < scale;i = next(i+1)){
					sb.append(",");
					sb.append(keys[i] + ":" + allocated[i]);
				}
				return sb.length() == 0 ? "" : sb.substring(1);
			}
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new F3().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.io.*;
import java.util.*;
import static java.lang.System.*;
import static java.lang.Math.*;
public class Code
{
    int P1,P2,H,S;
    long T1,T2;
    void run() {
        int tc=1;
        StringBuilder sb=new StringBuilder();
        while(tc-->0) {
            P1=ni(); T1=nl();
            P2=ni(); T2=nl();
            H=ni(); S=ni();
            long g = gcd(T1, T2);
            if (g > 1) {
              T1 /= g;
              T2 /= g;
            }
            if(T1>T2) {
                P1^=P2^(P2=P1);
                T1^=T2^(T2=T1);
            }
            if (T1 == T2) {
                int d = P1+P2-S;
                int round = (H + d - 1) / d;
                sb.append(round * T1 * g).append("\n");
                break;
            }
            dp = new Long[H+1];
            Arrays.fill(dp, (long) 1e16);
            // dp = new HashMap<>();
            int d1 = P1-S;
            int d2 = P2-S;
            int d = P1+P2-S;
            for(int v=1;v<=H;v++) {
                int r=v;
                long t1=T1,t2=T2;
                while(true) {
                    if(t1<t2) {
                        if(d1>=r) {
                            dp[v]=min(dp[v], t1);
                            break;
                        }
                        if(t1+T1<=t2) {
                            r-=d1;
                        }
                        else {
                            if(d>=r) {
                                dp[v]=min(dp[v], t2);
                            }
                            else {
                                dp[v]=min(dp[v], t2+dp[r-d]);
                            }
                            r-=d1;
                        }
                        t1+=T1;
                    }
                    else if(t1==t2) {
                        if(d>=r) {
                            dp[v]=min(dp[v], t2);
                        }
                        else {
                            dp[v]=min(dp[v], t2+dp[r-d]);
                        }
                        break;
                    }
                    else {
                        if(d2>=r) {
                            dp[v]=min(dp[v], t2);
                            break;
                        }
                        if(d>=r) {
                            dp[v]=min(dp[v], t1);
                        }
                        else {
                            dp[v]=min(dp[v], t1+dp[r-d]);
                        }
                        r-=d2;
                        t2+=T2;
                    }
                }
            }

            // solve(P1, T1, P2, T2, H, S);
            sb.append(dp[H]*g).append("\n");
        }
        out.println(sb);
        out.flush();
        out.close();
    }
    Long dp[], ans=Long.MAX_VALUE;
    // // Map<String, Long> dp;
    // long solve(int p1, long t1, int p2, long t2, int h, int s) {
    //     if(h<=0) return 0;

    //     if(dp[h]!=null) return dp[h];

    //     // int diff=Math.abs(c1-c2);
    //     // String str = concat(h);
    //     // if(dp.containsKey(str) && dp.get(str)) return dp.get(str);
    //     // 5000*5000=2.5*10^7

    //     if(t1>t2) {
    //         solve(p1, T1, p2, T2, h-(p1+p2-s), s);
    //         solve(p1, t1-t2, p2, T2, h-(p2-s), s);
    //         // res = min(x,y);
    //     }
    //     else {
    //         if(p1-s>=h) {
    //             ans=min(ans, t1);
    //             return ans;
    //         }
    //         if(t1+T1<=t2) {
    //             solve(p1, t1+T1, p2, t2, h-(p1-s), s);
    //         }
    //         else {
    //             if(p1+p2-s>=h) {
    //                 ans=min(ans, t2);
    //             }
    //             else {
    //                 ans=min(ans, t2+solve(p1, t1+T1, p2, t2, h-(p1+p2-s), s));
    //             }
    //         }
    //         // solve(p1, T1, p2, t2-t1, h-(p1-s), s, time+t1);
    //         // solve(p1, T1, p2, T2, h-(p1+p2-s), s, time+t2);
    //         // System.out.println(h+" "+x+" "+y);
    //         // res = min(x,y);
    //     }
    //     // dp.put(str, res);
    //     // return res;

    // }
    String concat(Long... v) {
        StringBuilder sb = new StringBuilder();
        for(Long i: v) sb.append(i).append(" ");
        return sb.toString();
    }
    StringBuilder pr(String s, int t) {
        return new StringBuilder().append("Case #").append(t).append(": ").append(s).append("\n");
    }
    public static void main(String[] args)throws Exception {
        try {
            // new Thread(null, new Code()::run, "1", 1 << 26).start();
            new Thread(null, new Code("ONLINE_JUDGE")::run, "1", 1 << 26).start();
        } catch(Exception e) {}
    }

    FastReader sc=null;PrintWriter out = null;
    public Code()throws Exception {
        sc = new FastReader(new FileInputStream("input.txt"));
        out = new PrintWriter(new BufferedWriter(new FileWriter("output.txt")));
    }
    public Code(String JUDGE) {
        sc = new FastReader(System.in);
        out = new PrintWriter(System.out);
    }

    String ns() { return sc.next(); }
    int ni() { return sc.nextInt(); }
    long nl() { return sc.nextLong(); }
    int[] ni(int n) {
        int a[]=new int[n];
        for(int i=0;i<n;a[i++]=ni());
        return a;
    }
    long[] nl(int n) {
        long a[]=new long[n];
        for(int i=0;i<n;a[i++]=nl());
        return a;
    }

    int[][] ni(int n,int m) {
        int a[][]=new int[n][m];
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                a[i][j]=ni();
        return a;
    }
    long[][] nl(int n,int m) {
        long a[][]=new long[n][m];
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                a[i][j]=nl();
        return a;
    }
    long gcd(long a, long b) {
        return b==0?a:gcd(b,a%b);
    }
    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private FastReader.SpaceCharFilter filter;
        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) return -1;
            }
            return buf[curChar++];
        }

        public int nextInt() {
            int c = read();
            while (isSpaceChar(c)) c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = read();
            }
            while (!isSpaceChar(c));
            return res * sgn;
        }

        public long nextLong() {
            int c = read();
            while (isSpaceChar(c)) c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9') throw new InputMismatchException();
                res = res*1L*10;
                res += c - '0';
                c = read();
            }
            while (!isSpaceChar(c));
            return res *1L* sgn;
        }

        public String next() {
            int c = read();
            while (isSpaceChar(c)) c = read();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) return filter.isSpaceChar(c);
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }
    }
}


import java.util.*;
public class E {

    int n = 300000000 + 2;
    byte []bits = new byte[n/16 + 1];
    boolean isset(int x){

        x >>= 1;
        int ind = x >> 3;
        int sh = x & 7;
        return (bits[ind] & (1 << sh)) != 0;
    }

    void setbit(int x){
        x >>= 1;
        int ind = x >> 3;
        int sh = x & 7;
        bits[ind] |= (1 << sh);
    }
    void seive(){

        for (int i = 3; i*i < n; i+=2) {
            if(!isset(i)){
                for (int j = i*i; j < n; j+=i+i) {
                        setbit(j);
                }
            }
        }
    }
    void read(){
        seive();
        Scanner s = new Scanner(System.in);
        int l = s.nextInt();
        int r = s.nextInt();
        int ans = 0;
        if(l <= 2 && r >= 2 ) ans ++;
        for (int i = 5; i <= n; i+=4) {
            if(l <= i && r >= i && !isset(i)){
                ans++;
            }
        }
        System.out.println(ans);
    }
    public static void main(String[] args) {
        new E().read();

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileNotFoundException;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author triveni
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		F solver = new F();
		solver.solve(1, in, out);
		out.close();
	}

	static class F {
		private Long[][] lastX = new Long[2010][2010];
		private long mod = 998244353;
		private long p = 0;
		private long[] pPow = new long[2010];
		private long[] qPow = new long[2010];
		private long[] strong = new long[2010];
		private Long[] dp = new Long[2010];

		public void solve(int testNumber, InputReader in, PrintWriter out) {
			int n = in.nextInt();
			int a = in.nextInt(), b = in.nextInt();
			p = MathUtils.powMod(b, mod - 2, mod) * a % mod;
			pPow[0] = 1;
			qPow[0] = 1;
			for (int i = 1; i < 2010; ++i) {
				pPow[i] = pPow[i - 1] * p % mod;
				qPow[i] = qPow[i - 1] * (1 - p + mod) % mod;
			}
			strong[1] = 1;
			for (int i = 2; i <= n; ++i) {
				long ans = 0;
				for (int j = 1; j < i; ++j) {
					ans += strong[j] * computeLastX(i, j) % mod;
					if (ans >= mod) ans -= mod;
				}
				strong[i] = 1 - ans;
				if (strong[i] < 0) strong[i] += mod;
			}
			long ans = dp(n);
			out.println(ans);
		}

		private long computeLastX(int n, int i) {
			if (lastX[n][i] != null) return lastX[n][i];
			if (n == i || i == 0) return lastX[n][i] = 1L;
			long ans = qPow[i] * computeLastX(n - 1, i) % mod + pPow[n - i] * computeLastX(n - 1, i - 1) % mod;
			return lastX[n][i] = ans % mod;
		}

		private long dp(int n) {
			if (dp[n] != null) return dp[n];
			if (n < 2) return dp[n] = 0L;
			if (n < 3) return dp[n] = 1L;
			long ans = strong[n] * (n * (n - 1) / 2) % mod;
			for (int x = 1; x < n; ++x) {
				long tmp = computeLastX(n, x) * strong[x] % mod;
				tmp *= (x * (x - 1) / 2 + x * (n - x) + dp(n - x) + dp(x)) % mod;
				ans += tmp % mod;
			}
			ans %= mod;
			ans *= MathUtils.powMod(1 + mod - strong[n], mod - 2, mod);
			return dp[n] = ans % mod;
		}

	}

	static class InputReader {
		public BufferedReader reader;
		public StringTokenizer tokenizer;

		public InputReader(InputStream inputStream) {
			reader = new BufferedReader(new InputStreamReader(inputStream));
			tokenizer = null;
		}

		public InputReader(String inputFile) throws FileNotFoundException {
			reader = new BufferedReader(new FileReader(inputFile));
			tokenizer = null;
		}

		public String nextLine() {
			String curr = "";
			try {
				curr = reader.readLine();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			return curr;
		}

		public String nextString() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(nextLine());
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(nextString());
		}

	}

	static class MathUtils {
		public static long powMod(long a, long b, long m) {
			long ans = 1;
			while (b > 0) {
				if (b % 2 == 1) ans = ans * a % m;
				b >>= 1;
				a = a * a % m;
			}
			return ans % m;
		}

	}
}


import java.io.*;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.sql.Time;
import java.util.*;

import java.math.BigInteger;

import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;

public class Main{

    void run(){
        Locale.setDefault(Locale.US);
        boolean oj = System.getProperty("ONLINE_JUDGE") != null;
//        boolean oj = true;
        try{
            if( oj ){
                sc  = new FastScanner( new InputStreamReader(System.in  ) );
                out = new PrintWriter(   new OutputStreamWriter(System.out) );
            } else{
                sc  = new FastScanner(new FileReader("in.txt") );
//                sc  = new FastScanner(new FileReader("D:\\JavaOlymp\\FatalError\\output.txt") );
                out = new PrintWriter(   new FileWriter("out.txt") );
            }
        } catch (Exception e) {
            System.exit(-1);
        }
        long tB = System.currentTimeMillis();
        solve();
        if( !oj ) System.err.println( "Time: " + (System.currentTimeMillis()-tB)/1e3 );
        out.flush();
    }

    class FastScanner{
        BufferedReader br;
        StringTokenizer st = new StringTokenizer("");
        FastScanner( InputStreamReader a ){
            br = new BufferedReader(a);
        }
        FastScanner( FileReader a ){
            br = new BufferedReader(a);
        }
        String next(){
            while( !st.hasMoreTokens() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    return null;
                }
            return st.nextToken();
        }
        String readLine(){
            try {
                return br.readLine();
            } catch (Exception e) {
                return null;
            }
        }
        int nextInt(){ return Integer.parseInt(next()); }
        long nextLong(){ return Long.parseLong(next()); }
    }

    FastScanner sc;
    PrintWriter out;

    public static void main(String[] args){
        new Main().run();
//        new Thread( null, new Runnable() {
//            @Override
//            public void run() {
//                new Main().run();
//            }
//            }, "LOL", 256L * 1024 * 1024 / 2 ).run();
//        }, "LOL", 2000 * 1024 * 1024 ).run();
    }

    void TLE(){ for(;;); }

    void MLE(){
        int[][] adj = new int[1024*1024][];
        for( int i = 0; i < adj.length; ++i )
            adj[i] = new int[1024*1024];
    }

    void exit( int val ){
        out.flush();
        System.exit(val);
    }
    //////////////////////////////////////////////////////////////////////////////////////////

    class Item{
        int i, j, msk;
        Item( int _i, int _j, int _msk ){
            i = _i;
            j = _j;
            msk = _msk;
        }
    }

    final int inf = Integer.MAX_VALUE / 10;
    int n, m, Si, Sj;
    char[][] gr;

    int timer, mskOfBomb;
    int[] idObj;

    int[] cost = new int[9];
    int[][] dp;

    void solve(){
        n = sc.nextInt();
        m = sc.nextInt();
        gr = new char[n][];
        idObj = new int[n*m]; fill( idObj, -1 );
        for( int i = 0; i < n; ++i )
            gr[i] = sc.next().toCharArray();

        int[] tmp = new int[9];
        for( int i = 1; ; ++i )
            try {
                tmp[i] = sc.nextInt();
            } catch (Exception e) {
                break;
            }

        for( int i = 0; i < n; ++i ){
            for( int j = 0; j < m; ++j ){
                char c = gr[i][j];
                if( Character.isDigit(c) ){
                    idObj[i*m+j] = timer++;
                    cost[timer-1] = tmp[c - '0'];
                }
                if( c=='B' ){
                    idObj[i*m+j] = timer++;
                    mskOfBomb |= 1 << (timer-1);
                }
                if( c == 'S' ){
                    Si = i;
                    Sj = j;
                }
            }
        }

        dp = new int[n*m][1<<8];
        for( int[] dpi : dp ) fill( dpi, inf );
        dp[Si*m + Sj][0] = 0;
        ArrayDeque<Item> Q = new ArrayDeque<Item>();
        Q.add(new Item(Si,Sj,0));
        while( !Q.isEmpty() ){
            Item v = Q.pollFirst();
            for( int di = -1; di <= 1; ++di ){
            for( int dj = -1; dj <= 1; ++dj ){
                if( abs(di) + abs(dj) != 1 ) continue;
                Item to = new Item(v.i+di, v.j+dj, v.msk);
                if(!( 0<=to.i && to.i<n &&
                      0<=to.j && to.j<m &&
                      (gr[to.i][to.j] == '.' || gr[to.i][to.j]=='S') ))
                    continue;
                if( abs(di)==1 ){
                    int curI = min(v.i, to.i);
                    for( int k = 0; k < v.j; ++k ){
                        int id = idObj[curI*m + k];
                        if( id != -1 ) to.msk ^= 1 << id;
                    }
                }
                if( dp[to.i*m + to.j][to.msk] > dp[v.i*m + v.j][v.msk] + 1 ){
                    dp[to.i*m + to.j][to.msk] = dp[v.i*m + v.j][v.msk] + 1;
                    Q.addLast(to);
                }
            }
            }
        }

        int ans = 0;
        for( int msk = 0; msk < 1<<8; ++msk ){
            if( (msk & mskOfBomb) == 0 &&
                    dp[Si*m + Sj][msk] != inf ){
                int cost = 0;
                for( int i = 0; i < 8; ++i )
                    if( (msk & (1<<i)) != 0 )
                        cost += this.cost[i];
                ans = max( ans, cost - dp[Si*m + Sj][msk] );
            }
        }

        out.println(ans);
    }

}


import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.util.Comparator;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.io.IOException;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.math.BigInteger;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author Egor Kulikov (egor@egork.net)
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		OutputWriter out = new OutputWriter(outputStream);
		TaskC solver = new TaskC();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskC {
	int RIGHT = 3;
	int LEFT = 1;

    public void solve(int testNumber, InputReader in, OutputWriter out) {
		int rowCount = in.readInt();
		int columnCount = in.readInt();
		char[][] table = IOUtils.readTable(in, rowCount, columnCount);
		int treasureCount = 0;
		int bombCount = 0;
		int sRow = -1;
		int sColumn = -1;
		for (int i = 0; i < rowCount; i++) {
			for (int j = 0; j < columnCount; j++) {
				char c = table[i][j];
				if (Character.isDigit(c))
					treasureCount = Math.max(treasureCount, c - '0');
				else if (c == 'B')
					bombCount++;
				else if (c == 'S') {
					sRow = i;
					sColumn = j;
				}
			}
		}
		table[sRow][sColumn] = '.';
		int[] value = IOUtils.readIntArray(in, treasureCount);
		int[][][] change = new int[4][rowCount][columnCount];
		int bombIndex = treasureCount;
		for (int i = 0; i < rowCount; i++) {
			for (int j = 0; j < columnCount; j++) {
				int curIndex = -1;
				if (Character.isDigit(table[i][j]))
					curIndex = table[i][j] - '1';
				else if (table[i][j] == 'B')
					curIndex = bombIndex++;
				if (curIndex == -1)
					continue;
				for (int k = 0; k < i; k++) {
					change[RIGHT][k][j] += 1 << curIndex;
					if (j + 1 < columnCount)
						change[LEFT][k][j + 1] += 1 << curIndex;
				}
			}
		}
		int count = treasureCount + bombCount;
		int[][][] cost = new int[rowCount][columnCount][1 << count];
		ArrayUtils.fill(cost, -1);
		cost[sRow][sColumn][0] = 0;
		int[] rowQueue = new int[rowCount * columnCount * (1 << count)];
		int[] columnQueue = new int[rowQueue.length];
		int[] maskQueue = new int[rowQueue.length];
		rowQueue[0] = sRow;
		columnQueue[0] = sColumn;
		int length = 1;
		for (int i = 0; i < length; i++) {
			int row = rowQueue[i];
			int column = columnQueue[i];
			int mask = maskQueue[i];
			for (int j = 0; j < 4; j++) {
				int nRow = row + MiscUtils.DX4[j];
				int nColumn = column + MiscUtils.DY4[j];
				int nMask = mask ^ change[j][row][column];
				if (!MiscUtils.isValidCell(nRow, nColumn, rowCount, columnCount) || table[nRow][nColumn] != '.' ||
					cost[nRow][nColumn][nMask] != -1)
				{
					continue;
				}
				cost[nRow][nColumn][nMask] = cost[row][column][mask] + 1;
				rowQueue[length] = nRow;
				columnQueue[length] = nColumn;
				maskQueue[length++] = nMask;
			}
		}
		int answer = 0;
		for (int i = 0; i < (1 << treasureCount); i++) {
			if (cost[sRow][sColumn][i] != -1) {
				int candidate = -cost[sRow][sColumn][i];
				for (int j = 0; j < treasureCount; j++) {
					if ((i >> j & 1) == 1)
						candidate += value[j];
				}
				answer = Math.max(answer, candidate);
			}
		}
		out.printLine(answer);
    }
}

class InputReader {

	private InputStream stream;
	private byte[] buf = new byte[1024];
	private int curChar;
	private int numChars;
	private SpaceCharFilter filter;

	public InputReader(InputStream stream) {
		this.stream = stream;
	}

	public int read() {
		if (numChars == -1)
			throw new InputMismatchException();
		if (curChar >= numChars) {
			curChar = 0;
			try {
				numChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (numChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int readInt() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public boolean isSpaceChar(int c) {
		if (filter != null)
			return filter.isSpaceChar(c);
		return isWhitespace(c);
	}

	public static boolean isWhitespace(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	public char readCharacter() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		return (char) c;
	}

	public interface SpaceCharFilter {
		public boolean isSpaceChar(int ch);
	}
}

class OutputWriter {
	private final PrintWriter writer;

	public OutputWriter(OutputStream outputStream) {
		writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
	}

	public OutputWriter(Writer writer) {
		this.writer = new PrintWriter(writer);
	}

	public void close() {
		writer.close();
	}

	public void printLine(int i) {
		writer.println(i);
	}
}

class IOUtils {

	public static int[] readIntArray(InputReader in, int size) {
		int[] array = new int[size];
		for (int i = 0; i < size; i++)
			array[i] = in.readInt();
		return array;
	}

	public static char[] readCharArray(InputReader in, int size) {
		char[] array = new char[size];
		for (int i = 0; i < size; i++)
			array[i] = in.readCharacter();
		return array;
	}

	public static char[][] readTable(InputReader in, int rowCount, int columnCount) {
		char[][] table = new char[rowCount][];
		for (int i = 0; i < rowCount; i++)
			table[i] = readCharArray(in, columnCount);
		return table;
	}

	}

class ArrayUtils {

	public static void fill(int[][] array, int value) {
		for (int[] row : array)
			Arrays.fill(row, value);
	}

	public static void fill(int[][][] array, int value) {
		for (int[][] subArray : array)
			fill(subArray, value);
	}

	}

class MiscUtils {
	public static final int[] DX4 = {1, 0, -1, 0};
	public static final int[] DY4 = {0, -1, 0, 1};

    public static boolean isValidCell(int row, int column, int rowCount, int columnCount) {
		return row >= 0 && row < rowCount && column >= 0 && column < columnCount;
	}

	}


import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Div1C {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt(), m = in.nextInt();
		char[][] g = new char[n][];
		for (int i = 0; i < n; i++)
			g[i] = in.next().toCharArray();
		Point start = null;
		int t = 0, b = 0;
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++) {
				if (Character.isDigit(g[i][j])) {
					t = Math.max(t, (int) (g[i][j] - '0'));
				} else if (g[i][j] == 'B') {
					b++;
				} else if (g[i][j] == 'S') {
					start = new Point(i, j);
				}
			}
		Point[] treasure = new Point[t];
		int[] value = new int[t];
		Point[] boom = new Point[b];
		for (int i = 0, bi = 0; i < n; i++)
			for (int j = 0; j < m; j++) {
				if (Character.isDigit(g[i][j])) {
					int ti = g[i][j] - '1';
					treasure[ti] = new Point(i, j);
				} else if (g[i][j] == 'B') {
					boom[bi++] = new Point(i, j);
				}
			}
		for (int ti = 0; ti < t; ti++)
			value[ti] = in.nextInt();
		int[][][][] cost = new int[n][m][1 << t][1 << b];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				for (int k = 0; k < (1 << t); k++) {
					for (int l = 0; l < (1 << b); l++) {
						cost[i][j][k][l] = 19930309;
					}
				}
			}
		}
		Queue<State> queue = new LinkedList<State>();
		State state = new State(start, 0, 0);
		cost[state.p.x][state.p.y][state.ts][state.bs] = 0;
		queue.add(state);
		while (!queue.isEmpty()) {
			state = queue.remove();
			final int[] dx = new int[] { 0, 0, 1, -1 };
			final int[] dy = new int[] { -1, 1, 0, 0 };
			for (int d = 0; d < 4; d++) {
				State nstate = new State(new Point(state.p.x + dx[d], state.p.y
						+ dy[d]), state.ts, state.bs);
				if (nstate.p.x >= 0 && nstate.p.x < n && nstate.p.y >= 0
						&& nstate.p.y < m
						&& !Character.isDigit(g[nstate.p.x][nstate.p.y])
						&& g[nstate.p.x][nstate.p.y] != '#'
						&& g[nstate.p.x][nstate.p.y] != 'B') {
					for (int i = 0; i < t; i++) {
						if (cross(treasure[i], state.p, nstate.p)) {
							nstate.ts ^= 1 << i;
						}
					}
					for (int i = 0; i < b; i++) {
						if (cross(boom[i], state.p, nstate.p)) {
							nstate.bs ^= 1 << i;
						}
					}
					if (cost[nstate.p.x][nstate.p.y][nstate.ts][nstate.bs] > cost[state.p.x][state.p.y][state.ts][state.bs] + 1) {
						cost[nstate.p.x][nstate.p.y][nstate.ts][nstate.bs] = cost[state.p.x][state.p.y][state.ts][state.bs] + 1;
						queue.add(nstate);
					}
				}
			}
		}
		int answer = 0;
		for (int ts = 0; ts < (1 << t); ts++) {
			int get = 0;
			for (int i = 0; i < t; i++)
				if ((ts & (1 << i)) != 0) {
					get += value[i];
				}
			get -= cost[start.x][start.y][ts][0];
			answer = Math.max(answer, get);
		}
		System.out.println(answer);
	}

	private static boolean cross(Point p, Point l1, Point l2) {
		return (l1.y > p.y) != (l2.y > p.y)
				&& p.x * (l2.y - l1.y) * (l2.y - l1.y) < (l2.x - l1.x)
						* (p.y - l1.y) * (l2.y - l1.y) + l1.x * (l2.y - l1.y)
						* (l2.y - l1.y);
	}
}

class Point {
	public int x, y;

	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

class State {
	Point p;
	public int ts, bs;

	public State(Point p, int ts, int bs) {
		this.p = p;
		this.ts = ts;
		this.bs = bs;
	}
}


import java.util.*;
import java.io.*;

public class Main {

	BufferedReader in;
	StringTokenizer str = null;
	PrintWriter out;

	private String next() throws Exception{
		if (str == null || !str.hasMoreElements())
			str = new StringTokenizer(in.readLine());
		return str.nextToken();
	}

	private int nextInt() throws Exception{
		return Integer.parseInt(next());
	}

	private long nextLong() throws Exception{
		return Long.parseLong(next());
	}

	private double nextDouble() throws Exception{
		return Double.parseDouble(next());
	}

	int dx[] = new int[]{1, 0, -1, 0};
	int dy[] = new int[]{0, -1, 0, 1};

	int n,m;
	char maze[][];
	int state[][];

	boolean used[][][];
	int d[][][];

	public void run() throws Exception{
		in =  new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);

		n = nextInt();
		m = nextInt();

		int sx = -1;
		int sy = -1;

		state = new int[n][m];

		int treasure = 0;
		maze = new char[n][m];
		for(int i=0;i<n;i++){
			maze[i] = next().toCharArray();
			for(int j=0;j<m;j++){
				if (maze[i][j] == 'S') {
					sx = i;
					sy = j;
					maze[i][j] = '.';
				}else if ('0' <= maze[i][j] && maze[i][j] <= '9') {
					int idx = maze[i][j] - '1';
					for(int k=j+1;k<m;k++){
						state[i][k]|=1<<idx;
					}
					treasure++;
				}
			}
		}

		int []a = new int[treasure];
		for(int i=0;i<treasure;i++) a[i] = nextInt();

		int sum[] = new int[1<<10];
		for(int i=0;i<1<<treasure;i++) {
			for(int j=0;j<treasure;j++) {
				if ((i & (1<<j)) > 0) {
					sum[i]+=a[j];
				}
			}
		}

		int bomb = treasure;
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				if (maze[i][j] == 'B') {
					for(int k=j+1;k<m;k++){
						state[i][k]|=1<<bomb;
					}
					bomb++;
				}
			}
		}

		used = new boolean[n][m][1<<bomb];
		d = new int[n][m][1<<bomb];

		bfs(sx, sy);
		int ans = 0;
		for(int i=0;i<1<<treasure;i++){
			if (used[sx][sy][i]) {
				ans = Math.max(ans, sum[i] - d[sx][sy][i]);
			}
		}

		out.println(ans);
		out.close();
	}

	Queue<int[]> q;

	private void bfs(int sx, int sy) {
		q = new LinkedList<int[]>();
		q.add(new int[]{sx, sy, 0});
		used[sx][sy][0] = true;
		d[sx][sy][0] = 0;

		while(q.size() > 0){
			int cur[] = q.poll();
			int x = cur[0], y = cur[1], nst = cur[2];

			for(int i=0;i<4;i++){
				int nx = x + dx[i], ny = y + dy[i], nstate = nst;
				if (!can(nx, ny)) continue;
				if (dx[i] == 1) {
					nstate^=state[nx][ny];
				}else if (dx[i] == -1) {
					nstate^=state[x][y];
				}

				if (used[nx][ny][nstate]) continue;
				used[nx][ny][nstate] = true;
				d[nx][ny][nstate] = d[x][y][nst] + 1;
				q.add(new int[]{nx, ny, nstate});
			}
		}
	}

	private boolean can(int x, int y) {
		if (x < 0 || y < 0) return false;
		if (x >=n || y >= m) return false;
		if (maze[x][y] != '.') return false;
		return true;
	}

	public static void main(String[] args) throws Exception{
		new Main().run();
	}
}


import java.io.*;
import java.math.BigInteger;
import java.util.*;

import static java.lang.Double.parseDouble;
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Integer.bitCount;
import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;

public class Main {
    public static void main(String[] args) throws IOException {
        Solver sv = new Solver();
        sv.solve();
    }
}

class Solver {
    BufferedReader in;
    StringTokenizer tok;

    public void solve() throws IOException {
        in = new BufferedReader(new InputStreamReader(System.in));

        int n = nextInt();
        int m = nextInt();
        String[] st = new String[n];
        int tr = 0, bomb = 0, sx = 0, sy = 0;
        int[] tx = new int [10];
        int[] ty = new int [10];
        int[] bx = new int [10];
        int[] by = new int [10];
        for(int i = 0; i < n; ++i) {
            st[i] = next();
            for(int j = 0; j < m; ++j) {
                char ch = st[i].charAt(j);
                if (ch >= '0' && ch <= '9') {
                    tx[ch - '0' - 1] = i;
                    ty[ch - '0' - 1] = j;
                    ++tr;
                }
                if (ch == 'B') {
                    bx[bomb] = i;
                    by[bomb] = j;
                    ++bomb;
                }
                if (ch == 'S') {
                    sx = i;
                    sy = j;
                }
            }
        }
        int[] cost = new int [tr];
        for(int i = 0; i < tr; ++i) {
            cost[i] = nextInt();
        }
        final int INF = Integer.MAX_VALUE;
        int[][][][] dist = new int [n][m][1 << tr][1 << bomb];
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                for(int t = 0; t < 1 << tr; ++t) {
                    for(int b = 0; b < 1 << bomb; ++b) {
                        dist[i][j][t][b] = INF;
                    }
                }
            }
        }
        dist[sx][sy][0][0] = 0;
        int[] Q = new int[20 * 20 * (1 << tr) * (1 << bomb) * 4];
        int l = 0,r = 0;
        Q[r++] = sx;
        Q[r++] = sy;
        Q[r++] = 0;
        Q[r++] = 0;

        final int[] dx = {1, 0, -1, 0};
        final int[] dy = {0, 1, 0, -1};

        while(l < r) {
            int x = Q[l++];
            int y = Q[l++];
            int t = Q[l++];
            int b = Q[l++];

            for(int d = 0; d < 4; ++d) {
                int nx = x + dx[d];
                int ny = y + dy[d];
                if (nx < 0 || ny < 0 || nx >= n || ny >= m) {
                    continue;
                }
                if (st[nx].charAt(ny) == '.' || st[nx].charAt(ny) == 'S') {
                    int nt = t;
                    int nb = b;
                    for(int i = 0; i < tr; ++i) {
                        if (intersects(tx[i], ty[i], x, y, nx, ny)) {
                            nt ^= (1 << i);
                        }
                    }
                    for(int i = 0; i < bomb; ++i) {
                        if (intersects(bx[i], by[i], x, y, nx, ny)) {
                            nb ^= (1 << i);
                        }
                    }
                    if (dist[nx][ny][nt][nb] == INF) {
                        dist[nx][ny][nt][nb] = dist[x][y][t][b] + 1;
                        Q[r++] = nx;
                        Q[r++] = ny;
                        Q[r++] = nt;
                        Q[r++] = nb;
                    }
                }
            }
        }

        int ans = 0;

        for(int t = 0; t < 1 << tr; ++t) {
            int d = dist[sx][sy][t][0];
            if (d == INF) {
                continue;
            }
            int cur = 0;
            for(int j = 0; j < tr; ++j) {
                if (((t >> j) & 1) == 1) {
                    cur += cost[j];
                }
            }
            ans = Math.max(ans, cur - d);
        }

        System.out.println(ans);
    }

    final double eps = 1e-7;

    boolean intersects(int sx, int sy, int ax, int ay, int bx, int by) {
        // (42, 43) ray from (sx, sy)

        int a1 = 43;
        int b1 = -42;
        int c1 = (sx + 42) * sy - sx * (sy + 43);

        int a2 = by - ay;
        int b2 = ax - bx;
        int c2 = bx * ay - ax * by;

        double det = a1 * b2 - a2 * b1;
        double detx = b1 * c2 - b2 * c1;
        double dety = a2 * c1 - c2 * a1;
        detx /= det;
        dety /= det;
        return detx > Math.min(ax, bx) - eps && detx < Math.max(ax, bx) + eps
                && dety > Math.min(ay, by) - eps && dety < Math.max(ay, by) + eps
                && detx > sx;
    }

    String next() throws IOException {
        if (tok == null || !tok.hasMoreTokens()) {
            tok = new StringTokenizer(in.readLine());
        }
        return tok.nextToken();
    }

    int nextInt() throws IOException {
        return parseInt(next());
    }

    long nextLong() throws IOException {
        return parseLong(next());
    }

    double nextDouble() throws IOException {
        return parseDouble(next());
    }
}


import java.io.*;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.sql.Time;
import java.util.*;

import java.math.BigInteger;

import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;

public class Main{

    void run(){
        Locale.setDefault(Locale.US);
        boolean oj = System.getProperty("ONLINE_JUDGE") != null;
//        boolean oj = true;
        try{
            if( oj ){
                sc  = new FastScanner( new InputStreamReader(System.in  ) );
                out = new PrintWriter(   new OutputStreamWriter(System.out) );
            } else{
                sc  = new FastScanner(new FileReader("in.txt") );
//                sc  = new FastScanner(new FileReader("D:\\JavaOlymp\\FatalError\\output.txt") );
                out = new PrintWriter(   new FileWriter("out.txt") );
            }
        } catch (Exception e) {
            System.exit(-1);
        }
        long tB = System.currentTimeMillis();
        solve();
        if( !oj ) System.err.println( "Time: " + (System.currentTimeMillis()-tB)/1e3 );
        out.flush();
    }

    class FastScanner{
        BufferedReader br;
        StringTokenizer st = new StringTokenizer("");
        FastScanner( InputStreamReader a ){
            br = new BufferedReader(a);
        }
        FastScanner( FileReader a ){
            br = new BufferedReader(a);
        }
        String next(){
            while( !st.hasMoreTokens() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    return null;
                }
            return st.nextToken();
        }
        String readLine(){
            try {
                return br.readLine();
            } catch (Exception e) {
                return null;
            }
        }
        int nextInt(){ return Integer.parseInt(next()); }
        long nextLong(){ return Long.parseLong(next()); }
    }

    FastScanner sc;
    PrintWriter out;

    public static void main(String[] args){
        new Main().run();
//        new Thread( null, new Runnable() {
//            @Override
//            public void run() {
//                new Main().run();
//            }
//            }, "LOL", 256L * 1024 * 1024 / 2 ).run();
//        }, "LOL", 2000 * 1024 * 1024 ).run();
    }

    void TLE(){ for(;;); }

    void MLE(){
        int[][] adj = new int[1024*1024][];
        for( int i = 0; i < adj.length; ++i )
            adj[i] = new int[1024*1024];
    }

    void exit( int val ){
        out.flush();
        System.exit(val);
    }
    //////////////////////////////////////////////////////////////////////////////////////////

    class Item{
        int i, j, msk;
        Item( int _i, int _j, int _msk ){
            i = _i;
            j = _j;
            msk = _msk;
        }
    }

    final int inf = Integer.MAX_VALUE / 10;
    int n, m, Si, Sj;
    char[][] gr;

    int timer, mskOfBomb;
    int[] idObj;

    int[] cost = new int[9];
    int[][] dp;
    int[][] howI = new int[1000][1000];
    int[][] howJ = new int[1000][1000];
    int[][] howM = new int[1000][1000];
    {
        for( int i = 0; i < 1000; ++i ){
            fill( howI[i], -1 );
            fill( howJ[i], -1 );
            fill( howM[i], -1 );
        }
    }

    void f( int i, int j, int msk ){
        if( i==Si && j==Sj && msk==0 ){
        }
        else{
            f(
                howI[i*m+j][msk],
                howJ[i*m+j][msk],
                howM[i*m+j][msk]);
        }
        out.printf("%d %d %4s\n", i, j, Integer.toBinaryString(msk));
    }

    void solve(){
        n = sc.nextInt();
        m = sc.nextInt();
        gr = new char[n][];
        idObj = new int[n*m]; fill( idObj, -1 );
        for( int i = 0; i < n; ++i )
            gr[i] = sc.next().toCharArray();

        int[] tmp = new int[9];
        for( int i = 1; ; ++i )
            try {
                tmp[i] = sc.nextInt();
            } catch (Exception e) {
                break;
            }

        for( int i = 0; i < n; ++i ){
            for( int j = 0; j < m; ++j ){
                char c = gr[i][j];
                if( Character.isDigit(c) ){
                    idObj[i*m+j] = timer++;
                    cost[timer-1] = tmp[c - '0'];
                }
                if( c=='B' ){
                    idObj[i*m+j] = timer++;
                    mskOfBomb |= 1 << (timer-1);
                }
                if( c == 'S' ){
                    Si = i;
                    Sj = j;
                }
            }
        }

        dp = new int[n*m][1<<8];
        for( int[] dpi : dp ) fill( dpi, inf );
        dp[Si*m + Sj][0] = 0;
        ArrayDeque<Item> Q = new ArrayDeque<Item>();
        Q.add(new Item(Si,Sj,0));
        while( !Q.isEmpty() ){
            Item v = Q.pollFirst();
            for( int di = -1; di <= 1; ++di ){
            for( int dj = -1; dj <= 1; ++dj ){
                if( abs(di) + abs(dj) != 1 ) continue;
                Item to = new Item(v.i+di, v.j+dj, v.msk);
                if(!( 0<=to.i && to.i<n &&
                      0<=to.j && to.j<m &&
                      (gr[to.i][to.j] == '.' || gr[to.i][to.j]=='S') ))
                    continue;
                if( abs(di)==1 ){
                    int curI = min(v.i, to.i);
                    for( int k = 0; k < v.j; ++k ){
                        int id = idObj[curI*m + k];
                        if( id != -1 ) to.msk ^= 1 << id;
                    }
                }
                if( dp[to.i*m + to.j][to.msk] > dp[v.i*m + v.j][v.msk] + 1 ){
                    dp[to.i*m + to.j][to.msk] = dp[v.i*m + v.j][v.msk] + 1;
                    Q.addLast(to);
                    howI[to.i*m + to.j][to.msk] = v.i;
                    howJ[to.i*m + to.j][to.msk] = v.j;
                    howM[to.i*m + to.j][to.msk] = v.msk;
                }
            }
            }
        }

        int ans = 0;
        for( int msk = 0; msk < 1<<8; ++msk ){
            if( (msk & mskOfBomb) == 0 &&
                    dp[Si*m + Sj][msk] != inf ){
                int cost = 0;
                for( int i = 0; i < 8; ++i )
                    if( (msk & (1<<i)) != 0 )
                        cost += this.cost[i];
                ans = max( ans, cost - dp[Si*m + Sj][msk] );
            }
        }

        out.println(ans);
    }

}


//package round221;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Queue;

public class C {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		char[][] map = nm(n,m);
		int sr = -1, sc = -1;
		int[][] objs = new int[8][];
		int p = 0;
		int max = 0;
		for(int i = 0;i < n;i++){
			for(int j = 0;j < m;j++){
				if(map[i][j] == 'S'){
					sr = i; sc = j;
					map[sr][sc] = '.';
				}
				if(map[i][j] >= '1' && map[i][j] <= '9'){
					objs[p++] = new int[]{i, j, map[i][j]-'0'};
					max = Math.max(max, map[i][j]-'0');
				}
				if(map[i][j] == 'B'){
					objs[p++] = new int[]{i, j, -99999};
				}
			}
		}
		int[] price = na(max);
		for(int i = 0;i < p;i++){
			if(objs[i][2] >= 0){
				objs[i][2] = price[objs[i][2]-1];
			}
		}

		int I = 999999;
		int[][][] d = new int[n][m][1<<p];
		for(int i = 0;i < n;i++){
			for(int j = 0;j < m;j++){
				Arrays.fill(d[i][j], I);
			}
		}
		d[sr][sc][0] = 0;
		Queue<Integer> q = new ArrayDeque<Integer>();
		q.add(enc(sr, sc, 0));
		int[] dr = { 1, 0, -1, 0 };
		int[] dc = { 0, 1, 0, -1 };
		while(!q.isEmpty()){
			int cur = q.poll();
			int r = cur>>>5&31, c = cur&31, ptn = cur>>>10;
			for(int k = 0;k < 4;k++){
				int nr = r + dr[k], nc = c + dc[k];
				if(nr >= 0 && nr < n && nc >= 0 && nc < m && map[nr][nc] == '.'){
					int nptn = ptn;
					if(k == 2){
						for(int u = 0;u < p;u++){
							if(objs[u][0] == r && objs[u][1] < c)nptn ^= 1<<u;
						}
					}
					if(k == 0){
						for(int u = 0;u < p;u++){
							if(objs[u][0] == nr && objs[u][1] < nc)nptn ^= 1<<u;
						}
					}
					if(d[nr][nc][nptn] > d[r][c][ptn] + 1){
						d[nr][nc][nptn] = d[r][c][ptn] + 1;
						q.add(enc(nr, nc, nptn));
					}
				}
			}
		}

		long ret = 0;
		for(int i = 0;i < 1<<p;i++){
			long tot = 0;
			for(int j = 0;j < p;j++){
				if(i<<31-j<0){
					tot += objs[j][2];
				}
			}
			ret = Math.max(ret, tot - d[sr][sc][i]);
		}
		out.println(ret);
	}

	int enc(int r, int c, int ptn)
	{
		return ptn<<10|r<<5|c;
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new C().run(); }

	private byte[] inbuf = new byte[1024];
	private int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package codeforces;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

public class C {
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    PrintWriter writer = new PrintWriter(System.out);
    StringTokenizer stringTokenizer;

    String next() throws IOException {
        while (stringTokenizer == null || !stringTokenizer.hasMoreTokens()) {
            stringTokenizer = new StringTokenizer(reader.readLine());
        }
        return stringTokenizer.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    long nextLong() throws IOException {
        return Long.parseLong(next());
    }

    void solve() throws IOException {
        int n = nextInt();
        int m = nextInt();
        char[][] map = new char[n][];
        int bombs = 0;
        int treasures = 0;
        for (int i = 0; i < n; i++) {
            map[i] = next().toCharArray();
            for (int j = 0; j < m; j++) {
                if (map[i][j] == 'B') bombs++;
                if (map[i][j] >= '0' && map[i][j] <= '9') {
                    treasures++;
                    map[i][j]--;
                }
            }
        }
        int[] treasureCosts = new int[treasures];
        for (int i = 0; i < treasures; i++) {
            treasureCosts[i] = nextInt();
        }
        class Point {
            int x, y;

            Point(int x, int y) {
                this.x = x;
                this.y = y;
            }

            Point subtract(Point other) {
                return new Point(x - other.x, y - other.y);
            }

            int vectorProduct(Point other) {
                return x * other.y - y * other.x;
            }

            Point add(Point other) {
                return new Point(x + other.x, y + other.y);
            }
        }
        class GeomUtils {
            Point cellCenter(int row, int column) {
                return new Point(2 * row + 1, 2 * column + 1);
            }

            Point ray = new Point(40, 41);

            double getT(Point o, Point v, Point s1, Point s2) {
                Point vs = s2.subtract(s1);
                int r = vs.vectorProduct(s2) - vs.vectorProduct(o);
                int l = vs.vectorProduct(v);
                return 1.0 * r / l;
            }

            boolean intersects(Point o, Point s1, Point s2) {
                if (getT(o, ray, s1, s2) < 0.0) return false;
                double t = getT(s1, s2.subtract(s1), o, o.add(ray));
                return t >= 0.0 && t <= 1.0;
            }
        }
        Point[] treasureCoords = new Point[treasures];
        Point[] bombCoords = new Point[bombs];
        bombs = 0;
        int si = 0, sj = 0;
        GeomUtils geomUtils = new GeomUtils();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (map[i][j] == 'B') {
                    bombCoords[bombs++] = geomUtils.cellCenter(i, j);
                }
                if (map[i][j] >= '0' && map[i][j] <= '9') {
                    treasureCoords[map[i][j] - '0'] = geomUtils.cellCenter(i, j);
                }
                if (map[i][j] == 'S') {
                    si = i;
                    sj = j;
                }
            }
        }
        int[][][][] dist = new int[n][m][1 << treasures][1 << bombs];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                for (int k = 0; k < 1 << treasures; k++)
                    for (int l = 0; l < 1 << bombs; l++) dist[i][j][k][l] = Integer.MAX_VALUE;
        dist[si][sj][0][0] = 0;
        Queue<Integer> qi = new LinkedList<>(), qj = new LinkedList<>(), qt = new LinkedList<>(), qb = new LinkedList<>();
        qi.add(si);
        qj.add(sj);
        qt.add(0);
        qb.add(0);
        int[] di = {0, -1, 0, 1};
        int[] dj = {-1, 0, 1, 0};
        while (!qi.isEmpty()) {
            int i = qi.poll();
            int j = qj.poll();
            int tmask = qt.poll();
            int bmask = qb.poll();
            Point s1 = geomUtils.cellCenter(i, j);
            for (int k = 0; k < 4; k++) {
                int ii = i + di[k];
                int jj = j + dj[k];
                if (ii < 0 || ii >= n || jj < 0 || jj >= m || map[ii][jj] != '.' && map[ii][jj] != 'S') continue;
                int tm = 0;
                for (int ti = 0; ti < treasures; ti++) {
                    if (geomUtils.intersects(treasureCoords[ti], s1, geomUtils.cellCenter(ii, jj))) {
                        tm |= 1 << ti;
                    }
                }
                int bm = 0;
                for (int bi = 0; bi < bombs; bi++) {
                    if (geomUtils.intersects(bombCoords[bi], s1, geomUtils.cellCenter(ii, jj))) {
                        bm |= 1 << bi;
                    }
                }
                if (dist[ii][jj][tmask ^ tm][bmask ^ bm] == Integer.MAX_VALUE) {
                    dist[ii][jj][tmask ^ tm][bmask ^ bm] = dist[i][j][tmask][bmask] + 1;
                    qi.add(ii);
                    qj.add(jj);
                    qt.add(tmask ^ tm);
                    qb.add(bmask ^ bm);
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < 1 << treasures; i++) {
            if(dist[si][sj][i][0] == Integer.MAX_VALUE) continue;
            int tCost = 0;
            for (int j = 0; j < treasures; j++) {
                if (((i >> j) & 1) == 1) tCost += treasureCosts[j];
            }
            ans = Math.max(ans, tCost - dist[si][sj][i][0]);
        }
        writer.println(ans);
        writer.close();
    }

    public static void main(String[] args) throws IOException {
        new C().solve();
    }
}


import java.io.*;
import java.util.*;

public class Main implements Runnable {

	public void _main() throws IOException {
		final int infinity = 1000000000;
		// A ray that is not collinear with any of the (dx, dy)`s
		final int RAY_R = 31;
		final int RAY_C = 37;
		int height = nextInt();
		int width = nextInt();
		char[][] s = new char[height][];
		int sr = -1;
		int sc = -1;
		int numTreasures = 0;
		int numBombs = 0;
		int[][] treasureId = new int[height][width];
		int[][] bombId = new int[height][width];
		for (int r = 0; r < height; r++) {
			s[r] = next().toCharArray();
			for (int c = 0; c < width; c++) {
				if (s[r][c] == 'S') {
					sr = r;
					sc = c;
					s[r][c] = '.';
				}
				treasureId[r][c] = -1;
				if (Character.isDigit(s[r][c])) {
					treasureId[r][c] = s[r][c] - '1';
					++numTreasures;
				}
				bombId[r][c] = -1;
				if (s[r][c] == 'B') {
					bombId[r][c] = numBombs;
					++numBombs;
				}
			}
		}
		int[] treasureR = new int[numTreasures];
		int[] treasureC = new int[numTreasures];
		int[] bombR = new int[numBombs];
		int[] bombC = new int[numBombs];
		for (int r = 0; r < height; r++) {
			for (int c = 0; c < width; c++) {
				if (treasureId[r][c] >= 0) {
					int id = treasureId[r][c];
					treasureR[id] = r;
					treasureC[id] = c;
				}
				if (bombId[r][c] >= 0) {
					int id = bombId[r][c];
					bombR[id] = r;
					bombC[id] = c;
				}
			}
		}
		int[] cost = new int[numTreasures];
		for (int i = 0; i < numTreasures; i++) {
			cost[i] = nextInt();
		}
		int[] value = new int[1 << (numTreasures + numBombs)];
		for (int i = 1; i < value.length; i++) {
			int j = Integer.numberOfTrailingZeros(i);
			if (j < numTreasures) {
				value[i] = cost[j] + value[i ^ (1 << j)];
			} else {
				value[i] = -infinity;
			}
		}
		int qsize = height * width * (1 << (numTreasures + numBombs));
		int[] qr = new int[qsize];
		int[] qc = new int[qsize];
		int[] qmask = new int[qsize];
		int[][][] dist = new int[height][width][1 << (numTreasures + numBombs)];
		for (int r = 0; r < height; r++) {
			for (int c = 0; c < width; c++) {
				Arrays.fill(dist[r][c], infinity);
			}
		}
		dist[sr][sc][0] = 0;
		qr[0] = sr;
		qc[0] = sc;
		qmask[0] = 0;
		int qt = 0;
		int qh = 1;
		int ans = 0;
		while (qt < qh) {
			int r = qr[qt];
			int c = qc[qt];
			int mask = qmask[qt];
			++qt;
			if (r == sr && c == sc) {
				ans = Math.max(ans, value[mask] - dist[r][c][mask]);
			}
			for (int dr = -1; dr <= 1; dr++) {
				for (int dc = -1; dc <= 1; dc++) {
					if (dr == 0 ^ dc == 0) {
						int nr = r + dr;
						int nc = c + dc;
						if (nr < 0 || nr >= height || nc < 0 || nc >= width) continue;
						if (s[nr][nc] != '.') continue;
						int nmask = mask;
						for (int i = 0; i < numTreasures + numBombs; i++) {
							int or, oc;
							if (i < numTreasures) {
								or = treasureR[i];
								oc = treasureC[i];
							} else {
								or = bombR[i - numTreasures];
								oc = bombC[i - numTreasures];
							}
							int r1 = r - or;
							int c1 = c - oc;
							int r2 = nr - or;
							int c2 = nc - oc;
							if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0) continue;
							if (Integer.signum(cross(r1, c1, RAY_R, RAY_C)) == Integer.signum(cross(RAY_R, RAY_C, r2, c2))) {
								nmask ^= 1 << i;
							}
						}
						if (dist[nr][nc][nmask] > 1 + dist[r][c][mask]) {
							dist[nr][nc][nmask] = 1 + dist[r][c][mask];
							qr[qh] = nr;
							qc[qh] = nc;
							qmask[qh] = nmask;
							++qh;
						}
					}
				}
			}
		}
		out.println(ans);
	}

	private int cross(int x1, int y1, int x2, int y2) {
		return x1*y2 - x2*y1;
	}

	private BufferedReader in;
	private PrintWriter out;
	private StringTokenizer st;

	private String next() throws IOException {
		while (st == null || !st.hasMoreTokens()) {
			String rl = in.readLine();
			if (rl == null)
				return null;
			st = new StringTokenizer(rl);
		}
		return st.nextToken();
	}

	private int nextInt() throws IOException {
		return Integer.parseInt(next());
	}

	private long nextLong() throws IOException {
		return Long.parseLong(next());
	}

	private double nextDouble() throws IOException {
		return Double.parseDouble(next());
	}

	public static void main(String[] args) {
		Locale.setDefault(Locale.UK);
		new Thread(new Main()).start();
	}

	public void run() {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			//in = new BufferedReader(new FileReader("a.in"));
			//out = new PrintWriter(new FileWriter("a.out"));

			_main();

			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(202);
		}
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

/**
 * @author Don Li
 */
public class CirclingRoundTreasures {

    int INF = (int) 1e7;

    int[] dx = new int[]{-1, 0, 0, 1};
    int[] dy = new int[]{0, -1, 1, 0};

    void solve() {
        int n = in.nextInt(), m = in.nextInt();
        char[][] s = new char[n][];
        for (int i = 0; i < n; i++) s[i] = in.nextToken().toCharArray();

        int t = 0, b = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (s[i][j] >= '1' && s[i][j] <= '8') t++;
                else if (s[i][j] == 'B') b++;
            }
        }

        int[] v = new int[t + b];
        for (int i = 0; i < t; i++) v[i] = in.nextInt();

        int sx = -1, sy = -1;
        int[] X = new int[t + b], Y = new int[t + b];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (s[i][j] >= '1' && s[i][j] <= '8') {
                    int id = s[i][j] - '1';
                    X[id] = i;
                    Y[id] = j;
                } else if (s[i][j] == 'B') {
                    X[t] = i;
                    Y[t] = j;
                    v[t] = -INF;
                    t++;
                } else if (s[i][j] == 'S') {
                    sx = i;
                    sy = j;
                }
            }
        }

        int[] cost = new int[1 << t];
        for (int i = 0; i < 1 << t; i++) {
            for (int j = 0; j < t; j++) {
                if ((i & (1 << j)) > 0) cost[i] += v[j];
            }
        }

        int[][][] dp = new int[n][m][1 << t];
        for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) Arrays.fill(dp[i][j], INF);

        int ans = 0;
        Queue<int[]> qu = new LinkedList<>();
        qu.offer(new int[]{sx, sy, 0});
        dp[sx][sy][0] = 0;
        while (!qu.isEmpty()) {
            int[] a = qu.poll();
            int x = a[0], y = a[1], mask = a[2];
            if (x == sx && y == sy) {
                ans = Math.max(ans, cost[mask] - dp[x][y][mask]);
            }
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i], ny = y + dy[i];
                if (nx >= 0 && nx < n && ny >= 0 && ny < m && (s[nx][ny] == '.' || s[nx][ny] == 'S')) {
                    int nmask = mask;
                    for (int j = 0; j < t; j++) {
                        if (cross(x, y, nx, ny, X[j], Y[j])) nmask ^= 1 << j;
                    }
                    if (dp[nx][ny][nmask] > dp[x][y][mask] + 1) {
                        dp[nx][ny][nmask] = dp[x][y][mask] + 1;
                        qu.offer(new int[]{nx, ny, nmask});
                    }
                }
            }
        }
        out.println(ans);
    }

    boolean cross(int x1, int y1, int x2, int y2, int x, int y) {
        return x == x1 && y < y1 && x == x2 + 1 && y < y2 || x == x2 && y < y2 && x == x1 + 1 && y < y1;
    }

    public static void main(String[] args) {
        in = new FastScanner(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(System.out);
        new CirclingRoundTreasures().solve();
        out.close();
    }

    static FastScanner in;
    static PrintWriter out;

    static class FastScanner {
        BufferedReader in;
        StringTokenizer st;

        public FastScanner(BufferedReader in) {
            this.in = in;
        }

        public String nextToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(in.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(nextToken());
        }

        public long nextLong() {
            return Long.parseLong(nextToken());
        }

        public double nextDouble() {
            return Double.parseDouble(nextToken());
        }
    }
}