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