/*
PROBLEM: Count Valid Strings with Forbidden Adjacent Pairs
Given:
- N: length of string to generate
- M: number of forbidden adjacent character pairs
Task: Count strings of length N using letters 'a'-'z' where no two adjacent
characters form a forbidden pair.
Key Insight:
- If two characters are in a "forbidden pair", they cannot be next to each other
- Use Dynamic Programming with matrix exponentiation
- Group forbidden characters together using Union-Find
- Characters can follow each other ONLY if they're the same OR in different groups
Example:
N=3, M=1, forbidden pair: (a,b)
- "abc" is invalid (a followed by b)
- "bac" is invalid (b followed by a)
- "aac" is valid
- "cde" is valid
Approach:
1. Group characters that can't be adjacent using Union-Find
2. Build transition matrix: can character i be followed by character j?
3. Use matrix exponentiation to count all valid paths of length N
4. Sum all entries in result matrix
Time: O(T * (M + 26³ * log N))
*/
#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1e9 + 7;
// Union-Find: keeps track of which characters are in the same "forbidden group"
struct UF {
int p[26]; // parent of each character
int r[26]; // rank for union by rank optimization
UF() {
// Initially each character is its own parent
for (int i = 0; i < 26; i++) {
p[i] = i;
r[i] = 0;
}
}
// Find the root/leader of the group containing x
int find(int x) {
// Path compression: make all nodes point directly to root
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
// Merge two groups together
void join(int x, int y) {
int rx = find(x); // root of x's group
int ry = find(y); // root of y's group
if (rx == ry) return; // already in same group
// Union by rank: attach smaller tree under larger tree
if (r[rx] < r[ry]) swap(rx, ry);
p[ry] = rx;
if (r[rx] == r[ry]) r[rx]++;
}
};
// Matrix for counting transitions between characters
struct Mat {
long long m[26][26];
Mat(bool id = false) {
// Initialize all entries to 0
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
m[i][j] = 0;
}
}
// If identity matrix requested, set diagonal to 1
if (id) {
for (int i = 0; i < 26; i++) m[i][i] = 1;
}
}
};
// Multiply two matrices (standard matrix multiplication)
Mat mult(Mat a, Mat b) {
Mat res;
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
// Compute res[i][j] = sum of a[i][k] * b[k][j]
for (int k = 0; k < 26; k++) {
res.m[i][j] = (res.m[i][j] + a.m[i][k] * b.m[k][j]) % MOD;
}
}
}
return res;
}
// Fast exponentiation: compute matrix^n in O(log n) time
Mat pow(Mat a, long long n) {
Mat res(true); // Start with identity matrix
while (n > 0) {
// If n is odd, multiply result by current matrix
if (n & 1) res = mult(res, a);
// Square the matrix
a = mult(a, a);
// Divide n by 2
n >>= 1;
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
long long n; // string length
int m; // number of forbidden pairs
cin >> n >> m;
// Build union-find structure
// Characters in same group cannot be adjacent
UF uf;
for (int i = 0; i < m; i++) {
char a, b;
cin >> a >> b;
// Put a and b in same group (they're forbidden to be adjacent)
uf.join(a - 'a', b - 'a');
}
// Edge case: empty string has exactly 1 way (the empty string itself)
if (n == 0) {
cout << 1 << "\n";
continue;
}
// Edge case: single character can be any of 26 letters
if (n == 1) {
cout << 26 << "\n";
continue;
}
// Build transition matrix
// trans[i][j] = 1 means character i can be followed by character j
Mat trans;
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
// Characters can be adjacent if:
// 1. They are the same character (i == j), OR
// 2. They belong to different forbidden groups
if (i == j || uf.find(i) != uf.find(j)) {
trans.m[i][j] = 1;
}
}
}
// Matrix exponentiation to count paths
// trans^(n-1) gives us count of all valid sequences of length n
// Why n-1? First character is "free", then we make n-1 transitions
Mat res = pow(trans, n - 1);
// Sum all entries in result matrix
// res[i][j] = number of valid strings starting with char i and ending with char j
// Total answer = sum over all possible (start, end) pairs
long long ans = 0;
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
ans = (ans + res.m[i][j]) % MOD;
}
}
cout << ans << "\n";
}
return 0;
}