我们先统计分别在每一列均在两个矩阵出现的字母,然后从小到大排好序。
对于第一个样例来说,我们得到ACDW、BOP、GMOX、AP、GSU
第一个字母无论以什么开头 后面都有3*4*2*3=72种可能 当k<=72时 以a开头 73<=k<=144时第一个字母为C
tot为后面的全排列 tot/=cnt[i] 则第i个字符因取第j个 j=k/tot (下取整,所以k-- 保证(72-1)/72 和(71-1)/72都为取a字符) k-=tot*j
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
const int N=10;
char x[N][N],y[N][N];
int cnt[N];
vector<char> v[N];
void input()
{
for(int i=1;i<=6;i++)
{
for(int j=1;j<=5;j++)
{
cin>>x[i][j];
}
}
for(int i=1;i<=6;i++)
{
for(int j=1;j<=5;j++)
{
cin>>y[i][j];
}
}
}
int init()
{
for(int i=1;i<=5;i++)
v[i].clear();
for(int col=1;col<=5;col++) //找到可能的密码
{
for(int r1=1;r1<=6;r1++)
{
for(int r2=1;r2<=6;r2++)
{
if(x[r1][col]==y[r2][col])
{
v[col].push_back(x[r1][col]);
}
}
}
}
for(int i=1;i<=5;i++)
{
if(v[i].empty()) return 0;
sort(v[i].begin(),v[i].end());
unique(v[i].begin(),v[i].end());
cnt[i]=0;//第i列有多少个
while(cnt[i]<v[i].size()-1&&v[i][cnt[i]+1]>v[i][cnt[i]])
{
cnt[i]++;
}
cnt[i]++;
}
return 1;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int k;//第k小
cin>>k;
input();
if(!init())
{
cout<<"NO"<<endl;
continue;
}
int tot=1;
for(int i=1;i<=5;i++)
tot*=cnt[i];
if(tot<k)
{
cout<<"NO"<<endl;
continue;
}
k--;//vector中下标从0开始
for(int i=1;i<=5;i++)//确定第i位上的密码
{
tot/=cnt[i];//后面的最大排列
//字典序x大于a开头最大,小于b开头最大 则x为以b开头.
//k大于j-1开头的最大&&小于j开头最大
int j=k/tot;//下取整
cout<<v[i][j];
k-=j*tot;
}
cout<<endl;
}
return 0;
}