n,m=map(int,input().split())
A=list(map(int,input().split()))
B=[0]
for i in range(n):
  B.append((B[-1]+A[i])%m)
C=[]


class TreeNode(object): 
  def __init__(self, val): 
    self.val = val 
    self.left = None
    self.right = None
    self.height = 1
class AVL_Tree(object): 
  def insert(self, root, key): 
  
    # 2分探索木の挿入を再帰的に行う。
    if not root: 
      return TreeNode(key) 
    elif key < root.val: 
      root.left = self.insert(root.left, key) 
    else: 
      root.right = self.insert(root.right, key) 
    # Step 2 - 現在のノードは新しく挿入されたノードの祖先になっている。現在のノードの高さを更新する。
    root.height = 1 + max(self.getHeight(root.left), self.getHeight(root.right)) 
    # Step 3 - 現在のノードの平衡係数（左の部分木の高さ – 右の部分木の高さ）を取得する。
    balance = self.getBalance(root) 
    # Step 4 - 
        # 平衡係数が1より大きい場合は、現在のノードは不均衡なので、 Left Left case か left Right case の回転を行う。
        # 平衡係数-1より小さい場合は、 現在のノードは不均衡なので、 Right Right case か Right Left case の回転を行う。
    # Case 1 - Left Left 
    if balance > 1 and key < root.left.val: 
      return self.rightRotate(root) 
    # Case 2 - Right Right 
    if balance < -1 and key > root.right.val: 
      return self.leftRotate(root) 
    # Case 3 - Left Right 
    if balance > 1 and key > root.left.val: 
      root.left = self.leftRotate(root.left) 
      return self.rightRotate(root) 
    # Case 4 - Right Left 
    if balance < -1 and key < root.right.val: 
      root.right = self.rightRotate(root.right) 
      return self.leftRotate(root) 
    return root 
  
  def delete(self, root, key): 
    # Step 1 - 2分木探索の削除を再帰的に行う。
    if not root: 
      return root 
    elif key < root.val: 
      root.left = self.delete(root.left, key) 
    elif key > root.val: 
      root.right = self.delete(root.right, key) 
    else: 
      if root.left is None: 
        temp = root.right 
        root = None
        return temp 
      elif root.right is None: 
        temp = root.left 
        root = None
        return temp 
      temp = self.getMinValueNode(root.right) 
      root.val = temp.val 
      root.right = self.delete(root.right, temp.val) 
    # 現在のノードが葉の場合は以下の処理は必要ない。
    if root is None: 
      return root 
    # Step 2 - 現在のノードは新しく挿入されたノードの祖先になっている。現在のノードの高さを更新する。
    root.height = 1 + max(self.getHeight(root.left), 
              self.getHeight(root.right)) 
    # Step 3 - 現在のノードの平衡係数（左の部分木の高さ – 右の部分木の高さ）を取得する。
    balance = self.getBalance(root) 
    # Step 4 - If the node is unbalanced, 
    # then try out the 4 cases 
    # Case 1 - Left Left 
    if balance > 1 and self.getBalance(root.left) >= 0: 
      return self.rightRotate(root) 
    # Case 2 - Right Right 
    if balance < -1 and self.getBalance(root.right) <= 0: 
      return self.leftRotate(root) 
    # Case 3 - Left Right 
    if balance > 1 and self.getBalance(root.left) < 0: 
      root.left = self.leftRotate(root.left) 
      return self.rightRotate(root) 
    # Case 4 - Right Left 
    if balance < -1 and self.getBalance(root.right) > 0: 
      root.right = self.rightRotate(root.right) 
      return self.leftRotate(root) 
    return root 
  
  def leftRotate(self, z): 
        #     z                               y     
        #    /  \                            / \   
        #   T1   y                          z   T3    
        #       / \     - - - - - - - >    / \     
        #     T2  T3     Left Rotation    T1  T2   
    y = z.right 
    T2 = y.left 
    # 回転を行う。
    y.left = z 
    z.right = T2 
    # 高さを更新する。
    z.height = 1 + max(self.getHeight(z.left), self.getHeight(z.right)) 
    y.height = 1 + max(self.getHeight(y.left), self.getHeight(y.right)) 
    # 新しいrootを返す。 
    return y 
  def rightRotate(self, z): 
        
        #      z                               y
        #     / \     Right Rotation          /  \
        #    y   T3   - - - - - - - >        T1   z 
        #   / \                                  / \
        #  T1  T2                               T2  T3
    y = z.left 
    T3 = y.right 
    # 回転を行う。
    y.right = z 
    z.left = T3 
    # 高さを更新する。 
    z.height = 1 + max(self.getHeight(z.left), self.getHeight(z.right)) 
    y.height = 1 + max(self.getHeight(y.left), self.getHeight(y.right)) 
    # 新しいrootを返す。
    return y 
  def getHeight(self, root): 
    if not root: 
      return 0
    return root.height 
  def getBalance(self, root): 
    if not root: 
      return 0
    return self.getHeight(root.left) - self.getHeight(root.right) 
  def getMinValueNode(self, root): 
    if root is None or root.left is None: 
      return root 
    return self.getMinValueNode(root.left) 
  def inOrder(self, root): 
    if not root: 
      return
    self.inOrder(root.left) 
    C.append(int("{}".format(root.val)))
    self.inOrder(root.right) 
  
  def preOrder(self, root): 
    if not root: 
      return
    print("{} ".format(root.val), end="") 
    self.preOrder(root.left) 
    self.preOrder(root.right) 
  
myTree = AVL_Tree() 
root = None
for i in range(n+1):
  root=myTree.insert(root,B[i])

"""The constructed AVL Tree would be 
    　 30 
    　/  \ 
    20  　 40 
    / \     / \ 
  　10 　25 35　50
   /
  5
"""
# Inorder Traversal 
# 5 10 20 25 30 35 40 50
myTree.inOrder(root)

a=1
ans=0
for i in range(1,n+1):
  if C[i-1]==C[i]:
    a=a+1
    if i==n:
      ans=ans+a*(a-1)//2
  else:
    ans=ans+a*(a-1)//2
    a=1
  
print(ans)

### FIXED CODE ###

from collections import defaultdict
n,m=map(int,input().split())
A=list(map(int,input().split()))
B=[0]
for i in range(n):
  B.append((B[-1]+A[i])%m)
C=defaultdict(int)
for i in range(n+1):
  C[B[i]]+=1
ans=0
for key in C.values():
  ans+=key*(key-1)//2
print(ans)