Kevin_K的flag回收录00(2018年问题求解与程序设计第二次练习"C. Bear and Compressing"题解)

Kevin_K edited 5 年,4 月前

Flag:机房电脑不知道怎么跑Python3?我记事本都给你A掉.

End:bad end;Kevin_K:”怎么RE了?怎么WA on test 1了???”

:().

本题是codeforces上某题的加强版.
题面如下:

C. Bear and Compressing

Time limit per test: 2.0 seconds
Memory limit: 512 MB

Limak is a little polar bear. Polar bears hate long strings and thus they like to compress them. You should also know that Limak is so young that, for the small dataset, he knows only first six letters of the English alphabet: a, b, c, d, e and f.

You are given a set of q possible operations. Limak can perform them in any order, any operation may be applied any number of times. The i-th operation is described by a string a_i of length two and a string b_i of length one. No two of q possible operations have the same string a_i.

When Limak has a string s he can perform the i-th operation on s if the first two letters of s match a two-letter string a_i. Performing the i-th operation removes first two letters of s and inserts there a string b_i. See the notes section for further clarification.

You may note that performing an operation decreases the length of a string s exactly by 1. Also, for some sets of operations there may be a string that cannot be compressed any further, because the first two letters don’t match any a_i.

Limak wants to start with a string of length n and perform n - 1 operations to finally get a one-letter string a. In how many ways can he choose the starting string to be able to get a? Remember that Limak can use only letters he knows.

Input

The first line contains two integers n and q — the length of the initial string and the number of available operations.

The next q lines describe the possible operations. The i-th of them contains two strings a_i and b_i (|a_i| = 2, |b_i| = 1). It’s guaranteed that a_i \ne a_j for i \ne j.

Output

Print the number of strings of length n that Limak will be able to transform to string a by applying only operations given in the input.

As the number can be very large, output it modulo 10^9+7.

样例可以点上面给的链接到codeforces里去看.

题目大意

某个单词的开头两个字母可以通过某种法则变为一个字母,一个长度为n的单词最后变成了”a”,请问最开始的单词有多少种可能?(对$10^9+7$取模)

分析

最大的数据规模达到了$10^{18}$,即便是在EOJ,暴模肯定也出不了奇迹了.我以前一直有个误区,这种题一定是推出一个一劳永逸的公式来.这对解题造成了一定的障碍.其实可以借鉴EOJ另外一道题的思路:3428. EvenOdd.我们要成倍减小数据范围.
我们可以令长度为n的以第m个(0基)字母开头的不同的单词个数为$a_{(n,m)}$,再假定由第i个字母开头变为第j个字母开头的方法数为$b_{(i,j)}$,容易得到$$a_{(n,m)}=\sum_{i=0}^{25} {a_{(n-1,i)} \times b_{(i,m)}} \tag {1}$$
是不是很像矩阵乘法?我们抽象出两个矩阵:$$A_n=\begin{bmatrix} a_{(n,0)} & a_{(n,1)} & … & a_{(n,25)}\end{bmatrix}$$$$B=\begin{bmatrix} b_{(0,0)} & b_{(0,1)} & … &b_{(0,25)} \ b_{(1,0)} & b_{(1,1)} & … & b_{(1,25)} \ … & … & … & … \ b_{(25,0)} & b_{(25,1)} & … &b_{(25,25)} \end{bmatrix}$$由(1)易得$A_n=A_{n-1} B$,计算出$B^{2^n}$,本题终结(如果能调试的话www,QAQ,TuT).

Python3 Code:

MOD = 1000000007
C = 26  # 字母个数.
lgn = 66


def mul(a, b):  # 矩阵乘法.
    return [[sum([a[i][k] * b[k][j] for k in range(len(b))]) % MOD for j in range(len(b[0]))] for i in range(len(a))]


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

# 初始化:
e = [[0 for j in range(C)] for i in range(C)]

# 输入B:
for i in range(q):
    a, b = input().split()
    e[ord(b[0]) - ord('a')][ord(a[0]) - ord('a')] += 1

# 记下Bn(n为2的幂)
ans = [e]
for i in range(lgn):
    ans.append(mul(ans[-1], ans[-1]))

# res是答案.
res = [[0 if i else 1 for i in range(C)]]

# t是现在的基,n记得-1因为开始时就长1位.
t = 0
n -= 1
while n:
    if n % 2:
        res = mul(res, ans[t])  # 根据二进制决定是否乘矩阵.
    n //= 2
    t += 1

# 输出:
print(sum(res[0]) % MOD)

强行BE......我为什么要心血来潮(作死)写Python3呢?大概是Python矩阵乘法只要1行看起来很炫酷吧…QAQ

Comments

ultmaster

一边乘一边模就不需要大数了。

Kevin_K

没用大数.QAQ
~~(而且隐隐感觉不一边乘一边模会超时)~~
~~(还有EOJ好像不支持删除线?一人血书那啥…)~~