/*
1. dfs去枚举每一个位上的数值
2. 剪枝 K = 9 6 3 9+27 < m = 60
3. tag标记有解的情况
4. 要按照顺序输出 n, A递增
5. 求素数
6. 求最大公约数
7. 10位,int会溢出
*/
#include <iostream>
#include <cmath>
#include <unordered_set>
#include <set>
using namespace std;
bool tag; //tag判断是否有解
unordered_set<int> st; //哈希表
//最大公因数
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
//判断是否是素数
bool isPrime(int x)
{
if (x <= 1) return false;
int sq = sqrt(x);
for (int i = 2; i <= sq; i++)
{
if (x % i == 0) return false;
}
return true;
}
set<pair<int, int>> res; //会先按第一个数据进行从小到大排序,若第一个数据相同则按第二个数据排序
//u为遍历的位数
// k,m为天长地久数的位数和各位数字之和
//sum为各位之和,A为符合条件的数
void dfs(int u, int K, int m, int sum, int A)
{
//遍历位数大于条件要求位数则不满足条件,返回上一级
if (u > K) return;
//剩余的位数取最大值还是小于要求的各位数字之和,则不满足条件返回上一级
if (sum + (K - u) * 9 < m) return;
//位数相符
if (u == K)
{
//各位数字相符
if (sum == m)
{
//则找到了天长地久数A,从而算出B
int B = A + 1;
//再求出B的各位之和=n
int n = 0;
do
{
n += B % 10;
B /= 10;
} while (B);
//若存在满足条件的n,则说明有解
if (st.count(n))
{
tag = true;
//存放答案
res.insert({ n, A });
}
}
return;
}
//遍历每一位0~9判断所有的可能性
for (int i = 0; i <= 9; i++)
{
//第一位不能为0
if (!u && !i) continue;
dfs(u + 1, K, m, sum + i, A * 10 + i);
}
}
int main() {
int N; //测试数据数
cin >> N;
for (int i = 1; i <= N; i++)
{
//输出测试数据数:
printf("Case %d\n", i);
int K, m; //天长地久数的位数和各位数字之和
cin >> K >> m;
//tag判断是否有解
tag = false;
//预处理m, n
st.clear();
res.clear();
//通过条件:m与n的最大公约数是一个大于2的素数,找出所有n的可能性
//n=m+1,m=[1,89]
for (int n = 1; n <= 90; n++)
{
//求最大公因数
auto t = gcd(n, m);
if (t > 2 && isPrime(t))
{
st.insert(n);
}
}
// 深度搜索
dfs(0, K, m, 0, 0);
//判断输出
if (!tag) puts("No Solution");
else
{
//依次输出所有解
for (const auto& x : res)
{
printf("%d %d\n", x.first, x.second);
}
}
}
return 0;
}