题目来源:2020 Code Jam Round 1C Overrandomized.
日期:[2020年5月2日]
个人题集编号:[A4-1]
知识点:[思维、集合]
原题面:提交+官方解析
题意简述
某台服务器可以执行对数字 0~9 的哈希转换,具体操作就是它有一个由不同大写字母构成的长度为 10 的字符串 D,D[ k ] 就代表数字 k 可以用大写字母 D[k] 代替。
现在我们尝试通过 1e4 次询问,来确定字符串 D。
每一次询问具体步骤如下:
- 输入一个整数 M (M 是小于 U 位数,其实几位数不重要)给服务器;
- 服务器会随机选一个整数 N ,1 <= N <= M,我们不知道 N 具体值;
- 服务器返回一个字符串 R ,代表 N 每个位置上一一替换后的字符串。(N无前导零)
现在我们知道所有的 M 和所有的 R,目标是确定长度为 10 的字符串 D。
其中 2<=U<=16 。
解题思路
这题的题意可能很绕,而且数据上面没说全,本题共 3 个点,其中第一二个点如上所述,但是第三个点我们是不知道每次询问的 M 的,也就是说只知道服务器的回答 R,而 M 虽然存在却不告诉我们。
这样一来第一二个点和第三个点就完全是两种解题思路,我只做出来前两问,官网有完整解法。
对于前两问,我的思路是如果我能确定 1,我就可以通过排除 1 的字母,来确定 2(因为D 中所有字母都是不同的)的字母;于是我可以通过将 1 所有可能匹配的字母放在一个集合内(只有一个,因为 1<=N<=1时只有一种取法),2 所有可能匹配的字母放在第二个集合内(最多有两个字母,因为 N 只能取 1 或 2),3~9 依次类推。
单个元素的情况很好考虑,直接压入集合即可,下面考虑不是单个元素的情况。假设 ‘37 HR’ 那么 H 一定是属于 3 的集合内的,因为十位只能取1、2、3,而个位却可能取0~9,所以 R 的作用就小很多,但是却可以压入 0 对应的集合(因为没有前导零,我们只能通过非首位来确定 0 的集合)。而如果 ‘35 K’这时 K 就可能对应 0~9 的任意一个数了,我们忽略。
通过上述方法就可以确定 0~9 的所有可能的取值集合,我们的确定顺序是 1 至 9 再到 0。当然你可能会有疑问“如果所给数据不能通过首位确定 1~9 咋办,那岂不是要通过非首位确定?而我们又舍弃了非首位…。”我刚开始也有这种担忧,但是题意既然说必定有解,如果通过非首位确定集合,这个时候可能就有多解了,可以举个例子证明一下。
第三点粗略的看了一眼,好像牵扯到概率和某些数学定理,时间有限,就到此为止。
代码示例
只能过前两个点!!!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4;
set<char> s[11],s2[11];
bool vis[150];
void work(char x[],char op[]){
int n = strlen(x), m = strlen(op);
if(n != m) return;
s[x[0]-'0'].insert(op[0]);
for(int i = 1;i < n;i++) s2[x[i]-'0'].insert(op[i]);
//printf("%d %c\n",x[0]-'0',op[0]);
}
void solve(){
for(int i = 0;i < 10;i++) s[i].clear(),s2[i].clear();
char x[30], op[20], ans[30];
int u; memset(vis,0,sizeof vis);
scanf("%d",&u);
for(int i = 1;i <= N;i++){
scanf("%s%s",x,op);
work(x,op);
}
for(int i = 0;i < 10;i++)
for(set<char>::iterator it = s[i].begin();it != s[i].end();it++){
if(!vis[*it]) ans[i] = *it, vis[*it] = true;
}
for(set<char>::iterator it = s2[0].begin();it != s2[0].end();it++)
if(!vis[*it]) ans[0] = *it, vis[*it] = true;
for(int i = 0;i <= 9;i++) putchar(ans[i]);
puts("");
}
int main(){
int t; scanf("%d",&t);
for(int c = 1;c <= t;c++){
printf("Case #%d: ",c);
solve();
}
return 0;
}