1.题目描述:点击打开链接
2.解题思路:本题是经典的解码问题,根据题意,可以事先找出每一列的公共元素,计算出每一列的“梯度”,即从某一列的第一个公共字母跳到下一个要经历多少种排列数。由梯度即可推出密码。本题需要注意的是:1.判断公共元素时事先放到set中,防止重复添加元素。2.计算梯度时为了方便后续处理,可以令i处的梯度等于从第i列到最后一列所有的排列数。详细过程见代码注释地方。(凡是“注意”中的都是陷阱,坑了我好久才过==)
3.代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;
#define N 100000
int g1[6][5], g2[6][5];
int com[5][6];
int cnt[5];
int gre[5];
set<int>s[5];
int k;
void factor()
{
memset(com, 0, sizeof(com));
memset(cnt, 0, sizeof(cnt));
memset(gre, 0, sizeof(gre));
for (int i = 0; i < 5; i++)s[i].clear();
for (int i = 0; i < 5; i++)
{
int&num = cnt[i];
for (int j = 0; j < 6; j++)
for (int l = 0; l < 6; l++)
if (g1[j][i] == g2[l][i])
s[i].insert(g1[j][i]);//为了防止有重复元素添加到com数组,先预存储到set中
}
for (int i = 0; i < 5; i++)
{
int&num = cnt[i];
for (set<int>::iterator it = s[i].begin(); it != s[i].end(); it++)
com[i][num++] = *it;
}
gre[4] = cnt[4];//梯度,直接取所有的排列数
for (int i = 3; i >= 0; i--)
gre[i] = gre[i + 1] * cnt[i];
}
int main()
{
//freopen("test.txt", "r", stdin);
int t;
cin >> t;
while (t--)
{
memset(g1, 0, sizeof(g1));
memset(g2, 0, sizeof(g2));
cin >> k;
getchar();
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 5; j++)
scanf("%c", &g1[i][j]);
getchar();
}
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 5; j++)
scanf("%c", &g2[i][j]);
getchar();
}
factor();
if (k>gre[0])printf("NO\n");
else
{
k--;//修改为编号从0开始,方便计算
int w;
for (int i = 0; i < 4; i++)
{
w = com[i][k / gre[i + 1]];
printf("%c", w);
k %= gre[i + 1];
}
w = com[4][k % gre[4]];//最后一行单独处理
printf("%c\n",w);
}
}
return 0;
}
原文:http://blog.csdn.net/u014800748/article/details/43941611