n, m = map(int, input().split())
edges = [list(map(int, input().split())) for _ in range(m)]
boundary = []
for i, e in enumerate(edges):
boundary.append([e[0], 0, i])
boundary.append([e[1], 1, i])
boundary.sort()
num = [[0, 0, 0, 0]]#边界起点,边界起点到下一个边界点的覆盖次数,边界点的出现在起始点、终止点的次数;因为边界终止点不计入覆盖次数
i = 0
for b in boundary:
if b[1] == 0:
if b[0] == num[i][0]:
num[i][1] += 1
num[i][2] += 1
else:
num.append([b[0], num[i][1]+1, 1, 0])
i += 1
else:
if b[0] == num[i][0]:
num[i][1] -= 1
num[i][3] += 1
else:
num.append([b[0], num[i][1]-1, 0, 1])
i += 1
# print(num)
# 回溯方法搜索所有可能的选择方式
def dfs(ind, n_r):# 此处默认输入的n_r一定是合理的
if ind >= m:
# print(n_r)
return 1 #成功搜索完整个数组,没有中途中断,符合要求的一个解
# 不删除edge[ind]
# for i in range(1, len(n_r)-1):
# if n_r[i][1]<2:
# return 0 # 当前情况无法满足覆盖要求,后续不需要再搜索
N = dfs(ind+1, [nu[:] for nu in n_r])
# 删除edge[ind]
e = edges[ind]
for i in range(1, len(n_r)):
if n_r[i][0]==e[0]:
n_r[i][2] -= 1
if n_r[i][0]==e[1]:
n_r[i][3] -= 1
if n_r[i][0]>=e[0] and n_r[i][0]<e[1]:#删除某条边上对计数的贡献
n_r[i][1] -= 1
for i in range(1, len(n_r)-1):#这里漏掉最后一个点判断,循环后补上
if ((n_r[i][1]+n_r[i][3])<2) or (n_r[i][1]<2 and (n_r[i+1][0] - n_r[i][0])>2):
# print(n_r)
return N # 当前情况无法满足覆盖要求,后续不需要再搜索
if n_r[-1][3] < 2:#补上最后一个点判断
return N
# print(n_r)
N += dfs(ind+1, [nu[:] for nu in n_r])
return N
# 判断当前的num是否满足要求
for i in range(1, len(num)-1):#这里漏掉最后一个点判断,循环后补上
if ((num[i][1]+num[i][3])<2) or (num[i][1]<2 and (num[i+1][0] - num[i][0])>2):
print(0)
exit(0) # 当前情况无法满足覆盖要求,后续不需要再搜索
if num[-1][3] < 2:#补上最后一个点判断
print(0)
exit(0)
N = dfs(0, [nu[:] for nu in num])#二维数组num需要使用深拷贝,所以作了循环生成
# print(num)
print(N)