Harryxun/sft_time huggingface dataset:
### BUGGY CODE ###

S = input()
mod = (10**9 + 7)

A,B,C,Q = [], [], [], []
for i, s in enumerate(S):
    if s == 'A':
        A.append(i)
    elif s == 'B':
        B.append(i)
    elif s == 'C':
        C.append(i)
    else:
        Q.append(i)

import bisect
ans = 0
for b in B + Q:
    ai = bisect.bisect_left(A, b)
    qa = bisect.bisect_left(Q, b)
    a = (ai * (3 ** qa)) % mod
    if qa > 0:
        a += (3 ** (qa - 1) * qa) % mod

    ci = bisect.bisect_right(C, b)
    qc = bisect.bisect_right(Q, b)
    lc = len(C) - ci
    lqc = len(Q) - qc
    c = (lc * (3 ** lqc)) % mod
    if lqc > 0:
        c += (3 ** (lqc - 1) * lqc) % mod
    
    ans += (a * c) % mod

print(ans % mod)

### FIXED CODE ###

S = input()
n = len(S)
mod = (10**9 + 7)

dp = [[0] * 4 for _ in range(n + 1)]

dp[n] = [0, 0, 0, 1]
for i in range(n-1, -1, -1):
    if S[i] == '?':
        dp[i][3] =  dp[i+1][3] * 3 % mod
        dp[i][2] = (dp[i+1][2] * 3 + dp[i+1][3]) % mod
        dp[i][1] = (dp[i+1][1] * 3 + dp[i+1][2]) % mod
        dp[i][0] = (dp[i+1][0] * 3 + dp[i+1][1]) % mod
    elif S[i] == 'C':
        dp[i][3] =  dp[i+1][3] % mod
        dp[i][2] = (dp[i+1][2] + dp[i+1][3]) % mod
        dp[i][1] =  dp[i+1][1] % mod
        dp[i][0] =  dp[i+1][0] % mod
    elif S[i] == 'B':
        dp[i][3] =  dp[i+1][3] % mod
        dp[i][2] =  dp[i+1][2] % mod
        dp[i][1] = (dp[i+1][1] + dp[i+1][2]) % mod
        dp[i][0] =  dp[i+1][0] % mod
    elif S[i] == 'A':
        dp[i][3] =  dp[i+1][3]
        dp[i][2] =  dp[i+1][2]
        dp[i][1] =  dp[i+1][1]
        dp[i][0] = (dp[i+1][0] + dp[i+1][1]) % mod
print(dp[0][0])
### BUGGY CODE ###

import sys
from queue import *
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)

n, q = list(map(int, input().split()))

adjacent_list = [[] for i in range(n+1)]
for i in range(n - 1):
    a, b = map(int, input().split())
    adjacent_list[a].append(b)
    adjacent_list[b].append(a)
tree_value = [0]*(n+1)
for i in range(q):
    p, x = map(int, input().split())
    tree_value[p] += x
searched = set()
def dfs(node, count):
    searched.add(node)
    tree_value[node] += count
    for i in adjacent_list[node]:
        if i not in searched:
            dfs(i, tree_value[node])
dfs(1,0)
for i in range(1,n+1):
    print("{} ".format(tree_value[i]), end = "")


### FIXED CODE ###

import sys
from queue import *
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)

n, q = list(map(int, input().split()))

adjacent_list = [[] for i in range(n+1)]
for i in range(n - 1):
    a, b = map(int, input().split())
    adjacent_list[a].append(b)
    adjacent_list[b].append(a)
tree_value = [0]*(n+1)
for i in range(q):
    p, x = map(int, input().split())
    tree_value[p] += x
searched = set()
"""
def dfs(node, count):
    searched.add(node)
    tree_value[node] += count
    for i in adjacent_list[node]:
        if i not in searched:
            dfs(i, tree_value[node])
"""
used = [0 for i in range(n+1)]
que = Queue()
que.put(1)
while que.qsize() != 0:
    m = que.get()
    used[m] = 1
    for i in adjacent_list[m]:
        if not used[i]:
            tree_value[i] += tree_value[m]
            que.put(i)
for i in range(1,n+1):
    print("{} ".format(tree_value[i]), end = "")
### BUGGY CODE ###

n,m = map(int,input().split())
d = {}
for _ in range(m):
    a,b = map(int,input().split())
    d[a] = d.get(a,[]) + [b]
    d[b] = d.get(b,[]) + [a]
ans = 1
visited = set()
for i in range(1,n+1):
    if i in visited: continue
    stack = [i]
    visited.add(i)
    cur = 1
    while stack:
        node = stack.pop()
        for nei in d.get(node,[]):
            if nei not in visited:
                stack.append(nei)
                visited.add(nei)
                cur += 1
    ans = max(ans,cur)
print(ans)

### FIXED CODE ###

class UnionFind:
    def __init__(self,n):
        self.par = {i:i for i in range(1,n+1)}
        self.rank = {i:0 for i in range(1,n+1)}
        self.size = {i:1 for i in range(1,n+1)}

    def find(self,x):
        if x != self.par[x]:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self,x,y):
        px,py = self.find(x),self.find(y)
        res = 0
        if px != py:
            if self.rank[px] < self.rank[py]:
                self.par[px] = py
                self.size[py] += self.size[px]
                res = self.size[py]
            else:
                self.par[py] = px
                self.size[px] += self.size[py]
                if self.rank[px] == self.rank[py]:
                    self.rank[px] += 1
                res = self.size[px]
        return res

n,m = map(int,input().split())
ans = 1
uf = UnionFind(n)
for _ in range(m):
    a,b = map(int,input().split())
    ans = max(ans,uf.union(a,b))
print(ans)
### BUGGY CODE ###

s=input()
n=len(s)
N=[0]*2020
x=0
for i in reversed(range(n)):
    x+=int(s[i])*(10**(n-i-1))
    N[x%2019]+=1
ans=0
ans+=N[0]
for j in N:
    ans+=j*(j-1)//2
print(ans)

### FIXED CODE ###

from collections import defaultdict
s=input()
n=len(s)
N=defaultdict(int)
x=0
for i in reversed(range(n)):
    x+=int(s[i])*pow(10,(n-i-1),2019)
    x%=2019
    N[x]+=1
ans=N[0]
for j in N.values():
    ans+=j*(j-1)//2
print(ans)
### BUGGY CODE ###

from collections import deque

s=input()
query=int(input())

li_q = []
for _ in range(query):
    li_q.append(input().split())

rev = False
li_str = [s]
for q in li_q:
    if q[0] == '1':
        rev = not rev
    else:
        if q[1] == '1':
            if rev:
                li_str.append(q[2])
            else:
                q_str = deque(li_str)
                q_str.appendleft(q[2])
                li_str = list(q_str)
        else:
            if rev:
                q_str = deque(li_str)
                q_str.appendleft(q[2])
                li_str = list(q_str)
            else:
                li_str.append(q[2])
                
ans = ''.join(li_str)
if rev:
    ans = ans[::-1]
    
print(ans)

### FIXED CODE ###

from collections import deque

s=input()
query=int(input())

li_q = []
for _ in range(query):
    li_q.append(input().split())

rev = False
q_str = deque([s])
for q in li_q:
    if q[0] == '1':
        rev = not rev
    else:
        if q[1] == '1':
            if rev:
                q_str.append(q[2])
            else:
                q_str.appendleft(q[2])
        else:
            if rev:
                q_str.appendleft(q[2])
            else:
                q_str.append(q[2])

li_str = list(q_str)
ans = ''.join(li_str)
if rev:
    ans = ans[::-1]
    
print(ans)
### BUGGY CODE ###

n,m = map(int,input().split())
p = list(map(int,input().split()))
xy = [list(map(int,input().split())) for _ in range(m)]

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


uf = UnionFind(n)
ans = 0
for x,y in xy:
    uf.union(x-1,y-1)
for v in uf.all_group_members().values():
    li = []
    for i in v:
        if p[i]-1 in v:
            ans += 1

print(ans)


### FIXED CODE ###

import sys
input = sys.stdin.readline

def main():
    n,m = map(int,input().split())
    p = list(map(int,input().split()))
    xy = [list(map(int,input().split())) for _ in range(m)]

    class UnionFind(object):
        def __init__(self, n=1):
            self.par = [i for i in range(n)]
            self.rank = [0 for _ in range(n)]
            self.size = [1 for _ in range(n)]

        def find(self, x):
            if self.par[x] == x:
                return x
            else:
                self.par[x] = self.find(self.par[x])
                return self.par[x]

        def union(self, x, y):
            x = self.find(x)
            y = self.find(y)
            if x != y:
                if self.rank[x] < self.rank[y]:
                    x, y = y, x
                if self.rank[x] == self.rank[y]:
                    self.rank[x] += 1
                self.par[y] = x
                self.size[x] += self.size[y]

        def all_group_members(self):
            return_list = [list() for i in range(n)]
            for i in range(n):
              return_list[self.find(i)].append(i)
            return return_list

    uf = UnionFind(n)
    ans = 0
    for x,y in xy:
        uf.union(x-1,y-1)
    for v in uf.all_group_members():
        set1 = set()
        for i in v:
            set1.add(p[i]-1)
        ans += len(set(v)&set1)

    print(ans)

if __name__ == '__main__':
    main()
### BUGGY CODE ###

N = int(input().strip())
x = [[0 for x in range(N)] for x in range(N)]
for i in range(N-1):
     u, v, w = list(map(int, input().split()))
     x[u-1][v-1] = w
     x[v-1][u-1] = w


ret = {}
done = []

queue = [0]

for i in range(N):
    curr = queue.pop()
    if curr == 0:
        ret[0] = 0

    for j in range(N):
        if x[curr][j] > 0:
            if x[curr][j] %2 == 0:
                ret[j] = ret[curr]
            else:
                ret[j] = 0 if ret[curr] == 1 else 1
            if j not in done:
                queue.append(j)
    done.append(curr)


for i in range(N):
    print(ret[i])


### FIXED CODE ###

N = int(input().strip())
x = [[] for x in range(N)]
for i in range(N-1):
     u, v, w = list(map(int, input().split()))
     x[u-1].append([v-1, w%2])
     x[v-1].append([u-1,w%2])



ret = {}
done = [0 for x in range(N)]

queue = [0]

for i in range(N):
    curr = queue.pop()
    if curr == 0:
        ret[0] = 0

    for neigh in x[curr]:
        if done[neigh[0]] == 1:
            continue
        if neigh[1] % 2 == 0:
            ret[neigh[0]] = ret[curr]
        else:
            ret[neigh[0]] = 0 if ret[curr] == 1 else 1

        queue.append(neigh[0])
    done[curr] = 1


for i in range(N):
    print(ret[i])
### BUGGY CODE ###

import sys
input=sys.stdin.readline
sys.setrecursionlimit(10**6)

def main():
    n=int(input().rstrip())
    a=[int(i) for i in input().split()]
    maxn=10**6+1
    dp=[True]*(maxn)
    cnt=[0]*(maxn)
    ans=0
    for i in a:
        if dp[i]:
            cnt[i]+=1
            for j in range(i*2,maxn,i):
                dp[j]=False

    for i in a:
        if dp[i] and cnt[i]==1:
            #print(i)
            ans+=1
    print(ans)

if __name__=="__main__":main()

### FIXED CODE ###

import sys
input=sys.stdin.readline
sys.setrecursionlimit(10**6)

N=int(input().rstrip())
a=[int(i) for i in input().split()]
l=max(a)+1
cnt=[0]*l
for i in a:
    for j in range(i,l,i):cnt[j]+=1

ans=0
for i in a:
    if cnt[i]==1:
        ans+=1
print(ans)
### BUGGY CODE ###

def main():
    N=int(input())
    A=[input() for i in range(N)]
    NA=[A.count(A[i]) for i in range(N)]
    NIN=[i for i, v in enumerate(NA) if v == max(NA)]
    NM=sorted(list(set([A[NIN[i]] for i in range (len(NIN))])))
    for i in range (len(NM)):
        print(NM[i])
if __name__ == '__main__':
    main()

### FIXED CODE ###

N = int(input())
L = [input() for i in range(N)]
L = sorted(L)
D = {}

for i in L:
    if i in D:
        V = D.get(i) + 1
    else:
        V = 1
    D[i] = V

D = sorted(D.items(),key=lambda x:x[1],reverse=True)

Ans = []

Ans.append(D[0][0])

for i in range(len(D)-1):
    if D[i][1] == D[i+1][1]:
        Ans.append(D[i+1][0])
    else:
        break

Ans = sorted(Ans)

for i in Ans:
    print(i)
### BUGGY CODE ###

# diverta 2019 Programming Contest: B – RGB Boxes
R, G, B, N = [int(i) for i in input().split()]

bingo = 0

for r in range(N + 1):
    if R * r > N:
        break
    for g in range(N + 1):
        b = (N - (R * r + G * g)) // B
        if b < 0:
            break
        if R * r + G * g + B * b == N:
            bingo += 1

print(bingo)

### FIXED CODE ###

# diverta 2019 Programming Contest: B – RGB Boxes
R, G, B, N = [int(i) for i in input().split()]

bingo = 0

for r in range(0, 3001):
    if R * r > N:
        break
    else:
        for g in range(0, 3001):
            b = (N -(R * r + G * g)) // B
            if b < 0:
                break
            elif R * r + G * g + B * b == N:
                bingo += 1

print(bingo)
### BUGGY CODE ###

N,T = map(int,input().split())
data = [list(map(int,input().split())) for _ in range(N)]

dp1 = [[0 for n in range(N+1)] for t in range(T+1)] #dp1[t][n] := (data[:n]の中からtまでに食べ切る範囲で美味しく）
dp2 = [[0 for n in range(N+1)] for t in range(T+1)] #dp1[t][n] := (data[:n]の中からt-1までに注文する範囲で美味しく)


for t in range(1,T+1):
    for n in range(1,N+1):
        if t-data[n-1][0] >= 0:
            dp1[t][n] = max(dp1[t][n-1],dp1[t-data[n-1][0]][n-1]+data[n-1][1])
            dp2[t][n] = max(dp2[t][n-1],dp2[t-data[n-1][0]][n-1]+data[n-1][1],dp1[t-1][n-1]+data[n-1][1])
        else:
            dp1[t][n] = dp1[t][n-1]
            dp2[t][n] = max(dp2[t][n-1],dp1[t-1][n-1]+data[n-1][1])


print(dp2[T][N])

### FIXED CODE ###

n,t = map(int,input().split())
data = [list(map(int,input().split())) for _ in range(n)]

dp1 = [[0 for i in range(n+1)] for j in range(t+1)]
dp2 = [[0 for i in range(n+1)] for j in range(t+1)]

q = 0
for i in range(1,n+1):
    q = max(q,data[i-1][0])
    dp2[1][i] = q

for i in range(1,t+1):
    for j in range(1,n+1):
        if i-data[j-1][0] >= 0:
            dp1[i][j] = max(dp1[i][j-1],dp1[i-data[j-1][0]][j-1]+data[j-1][1])
            dp2[i][j] = max(dp2[i][j-1],dp2[i-data[j-1][0]][j-1]+data[j-1][1],dp1[i-1][j-1]+data[j-1][1])
        else:
            dp1[i][j] = dp1[i][j-1]
            dp2[i][j] = max(dp2[i][j-1],dp1[i-1][j-1]+data[j-1][1])


print(dp2[t][n])
### BUGGY CODE ###

H, W, M = list(map(int, input().split()))

targets = set()
row = [0]*H
col = [0]*W

for _ in range(M):
    h, w = list(map(lambda x: int(x) - 1, input().split()))
    row[h] += 1
    col[w] += 1
    targets.add((h, w))

# for h in range(H):
#     for w in range(W):
#         row[h] += 1
#         col[w] += 1
#         targets.add((h, w))
# print('ready')

r_max = max(row)
c_max = max(col)
# print([h for h in range(H) if row[h] == r_max])
# print([w for w in range(W) if col[w] == c_max])
max_nearly = set([(h, w) for w in range(W) if col[w] == c_max for h in range(H) if row[h] == r_max])
if len(max_nearly - targets) == 0:
    # print('hoge')
    print(r_max + c_max - 1)
else:
    print(r_max + c_max)
    



### FIXED CODE ###

H, W, M = list(map(int, input().split()))

targets = set()
row = [0]*H
col = [0]*W

for _ in range(M):
    h, w = list(map(lambda x: int(x) - 1, input().split()))
    row[h] += 1
    col[w] += 1
    targets.add((h, w))

r_max = max(row)
c_max = max(col)
ans = 0

maxed_h = set([h for h in range(H) if row[h] == r_max])
maxed_w = set([w for w in range(W) if col[w] == c_max])
bomb_option_sites_n = len(maxed_h)*len(maxed_w)
targets_on_bomb_option = 0
for th, tw in targets:
    if th in maxed_h and tw in maxed_w:
        targets_on_bomb_option += 1

if bomb_option_sites_n == targets_on_bomb_option:
    print(r_max + c_max - 1)
else:
    print(r_max + c_max)
### BUGGY CODE ###

X = input()
for i in range(10**5):
    note = X
    X = X.replace("ST","")
    if note == X:
        break
print(len(X))

### FIXED CODE ###

X = input()
stack = []
for e in X:
    if e == "S":
        stack.append(e)
    elif stack == []:
        stack.append(e)
    elif stack[-1] == "T":
        stack.append(e)
    elif stack[-1] == "S":
        stack.pop(-1)
print(len(stack))
### BUGGY CODE ###

n = int(input())
a = [0]
a += list(map(int, input().split()))
a.append(0)
aa = []
for i in range(n+1):
    aa.append(abs(a[i] - a[i + 1]))
for i in range(n):
    print(sum(aa)-aa[i]-aa[i+1]+abs(a[i]-a[i+2]))

### FIXED CODE ###

n = int(input())
a = [0]
a += list(map(int, input().split()))
a.append(0)
ans = 0
for i in range(1, n + 1):
    ans += abs(a[i] - a[i + 1])
for i in range(n):
    ans -= abs(a[i+1]-a[i+2])
    print(ans+abs(a[i] - a[i + 2]))
    ans += abs(a[i] - a[i + 1])
### BUGGY CODE ###

x, y = map(int, input().split())

if x%y == 0:
    ans = -1
else:
    ans = 0
    cnt = 2
    while True:
        if (x*cnt)%y != 0:
            ans = x*cnt
            break

print(ans)

### FIXED CODE ###

x, y = map(int, input().split())

if x%y == 0:
    ans = -1
else:
    ans = 0
    cnt = 2
    while True:
        if (x*cnt)%y != 0:
            ans = x*cnt
            break
        else:
            cnt += 1

print(ans)
### BUGGY CODE ###

N,M = map(int,input().split())
A = list(input().split())

def cmp(a,b):
    if a == None:
        return True
    elif b == None:
        return False
    if len(a) > len(b):
        return False
    elif len(a) < len(b):
        return True
    else:
        if int(a) >= int(b):
            return False
        else:
            return True

dp = [-1] * (N+10)
l = [0,2,5,5,4,5,6,3,7,6]
dp[0] = 0
for i in range(N-1):
    for s in A:
        if dp[i] == -1 and i!=0:
            continue
        if dp[i + l[int(s)]] < int(str(dp[i])+s):
            dp[i + l[int(s)]] = int(str(dp[i])+s)
            

print(dp[N])


                





### FIXED CODE ###

N,M = map(int,input().split())
A = list(map(int,input().split()))

dp = [-1 for i in range(N+10)]
l = [0,2,5,5,4,5,6,3,7,6]
dp[0] = 0
for i in range(N-1):
    for s in A:
        if dp[i] == -1 and i!=0:
            continue
        if dp[i + l[s]] < dp[i]*10+s:
            dp[i + l[s]] = dp[i]*10+s
print(dp[N])
### BUGGY CODE ###

n ,m ,k = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
 
sa = [0]
sb = [0]
 

for i in range(n):
    sa.append(sa[i]+a[i])
 
for i in range(m):
    sb.append(sb[i]+b[i])
 
ans = 0
 
for i in range(n+1):
    if sa[i] > k:
        break
    mb = 0
    lb = m+1
    for j in range(100):
        mid = (mb+lb)//2
        if sb[mid] + sa[i] <= k:
            mb = mid
        else:
            lb = mid
    ans = max(ans, i + mb)
 
print(ans)

### FIXED CODE ###

n ,m ,k = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))

sa = [0]
sb = [0]

for i in range(n):
    sa.append(sa[i]+a[i])

for i in range(m):
    sb.append(sb[i]+b[i])

ans = 0
j = m

#しゃくとり
for i in range(n+1):
    if sa[i] > k:
        break
    while sa[i]+sb[j] > k:
        j -= 1
    ans = max(ans, i+j)

print(ans)
### BUGGY CODE ###

N = int(input())
D = [list(map(int,input().split()))+[k] for k in range(N)]

T = sorted(D, key = lambda x: (-x[0],-x[1]))
A = sorted(D, key = lambda x: (-x[1],-x[0]))
U = [1 for k in range(N)]

ans = 0
l = 0
m = 0
for k in range(N):
    if k%2 == 0:
        while U[T[l][2]] == 0:
            l += 1
        ans += T[l][0]
        U[T[l][2]] = 0
    else:
        m = 0
        while U[A[m][2]] == 0:
            m += 1
        ans -= A[m][1]
        U[A[m][2]] = 0

print(ans)


### FIXED CODE ###

N = int(input())
D = [list(map(int,input().split()))+[k] for k in range(N)]

T = sorted(D, key = lambda x: x[0]+x[1], reverse = True)
A = sorted(D, key = lambda x: x[1]+x[0], reverse = True)
U = [1 for k in range(N)]

ans = 0
l = 0
m = 0
for k in range(N):
    if k%2 == 0:
        while U[T[l][2]] == 0:
            l += 1
        ans += T[l][0]
        U[T[l][2]] = 0
    else:
        while U[A[m][2]] == 0:
            m += 1
        ans -= A[m][1]
        U[A[m][2]] = 0

print(ans)
### BUGGY CODE ###

import sys
sys.setrecursionlimit(10**8)
n,w=map(int,input().split())
l=[]
for i in range(n):
  l.append(list(map(int,input().split())))
dp=[[-1 for i in range(w+1)] for j in range(n+1)]
def knap(x,y):
  if dp[x][y]!=-1:
    return dp[x][y]
  if x==n:
    res=0
  elif y<l[x][0]:
    res=knap(x+1,y)
  else:
    res=max(knap(x+1,y),knap(x+1,y-l[x][0])+l[x][1])
  dp[x][y]=res
  return res
knap(0,w)
print(dp[0][w])

### FIXED CODE ###

import sys
sys.setrecursionlimit(10**8)
def knapsack(N,W,weight,value):
  #初期化
  inf=float("inf")
  dp=[[-inf for i in range(W+1)] for j in range(N+1)]
  for i in range(W+1): dp[0][i]=0

  #DP
  for i in range(N):
    for w in range(W+1):
      if weight[i]<=w: #dp[i][w-weight[i]の状態にi番目の荷物が入る可能性がある
        dp[i+1][w]=max(dp[i][w-weight[i]]+value[i], dp[i][w])
      else: #入る可能性はない
        dp[i+1][w]=dp[i][w]
  return dp[N][W]
n1,w1=map(int,input().split())
lw=[]
lv=[]
for i in range(n1):
  w,v=map(int,input().split())
  lw.append(w)
  lv.append(v)
print(knapsack(n1,w1,lw,lv))
### BUGGY CODE ###

from collections import deque

H,W=map(int, raw_input().split() )
S=[ raw_input() for i in range(H) ] 


D=[ (1,0), (-1,0), (0,1), (0,-1) ] 


ret=0
q = deque([]) 
V=[ [ 0 for i in range(W) ] for j in range(H) ]

def dfs(x,y,current):
	ret=0
	V[x][y]=1
	q.append( (x,y,current) )
	
	while q:
		x,y,current=q.pop()
		if S[x][y]==".":
			ret+=1
		V[x][y]=1
		for dx,dy in D:
			if 0<=x+dx<H and 0<=y+dy<W:
				if V[x+dx][y+dy]==0 and S[x+dx][y+dy] != current:
					if (x+dx, y+dy, S[x+dx][y+dy] ) not in q:
						q.append( (x+dx, y+dy, S[x+dx][y+dy] ) )	
	return ret



ans=0
for x in range(H):
	for y in range(W):
		if S[x][y]=="#":
			ret=0
			q = deque([]) 
			V=[ [ 0 for i in range(W) ] for j in range(H) ]
			ans+=dfs(x,y, "#")

print ans


### FIXED CODE ###

from collections import deque

H,W=map(int, raw_input().split() )
S=[ raw_input() for i in range(H) ] 


D=[ (1,0), (-1,0), (0,1), (0,-1) ] 


V=[ [ 0 for i in range(W) ] for j in range(H) ]


def dfs(x,y,current):
	bc=0	#black count
	wc=0	#white count
	q = deque([]) 
	V[x][y]=1
	q.append( (x,y,current) )

	while q:
		x,y,current=q.popleft()

		if current == "#":	  bc+=1
		else:  wc+=1

		for dx,dy in D:
			if 0<=x+dx<H and 0<=y+dy<W:
				next=S[x+dx][y+dy] 
				if V[x+dx][y+dy]==0 and current !=next:
						V[x+dx][y+dy]=1
						q.append( (x+dx, y+dy,next) )

	return bc*wc




ans=0
for x in range(H):
	for y in range(W):
		if S[x][y]=="#" and V[x][y]==0:
			ans+=dfs(x,y, "#")

print ans