猜词题解
假设你会一点点信息论,因为做这道题的人一定知道这是一道信息论题。
如果不会的话,你可以观看这两个视频:https://www.bilibili.com/video/BV1yVNU6xERx/,https://www.bilibili.com/video/BV1zZ4y1k7Jw/。
理论上每次我们应选信息熵最大的一个单词,一个单词的信息熵是:
这里 g 是 s 是
我们有两个集合 guess 前,我们应适当地从
然后我们枚举
但显然此时时间复杂度是
计算熵最慢的是第一次 guess,但它可以很方便的打表解决,然后剩下的部分就跑得很快了。
但这个时候我们还不能 AC。比如在最后的查询中,只剩下两个单词
于是我们改变熵的求法:
也就是加上了这个单词正确的概率乘
#include<bits/stdc++.h>
std::vector<std::string> table, st;
std::string ans_fir[26]={"slier", "lares", "lares", "tores", "tarns", "arles", "lares", "lares", "snare", "ousel", "ranis", "nares", "tares", "aides", "tries", "lares", "raise", "aides", "plate", "nares", "snare", "riles", "nares", "cones", "kanes", "aeons"}; // 打表
int n;
int siz;
void init(int num_scramble, const char *scramble) {
n=num_scramble;
for(int i(0); i<n; i++) {
table.push_back("");
for(int j(0); j<5; j++) table.back().push_back(scramble[5*i+j]);
}
}
std::string las;
std::array<int,5> check(std::string appt, std::string ans) {
std::array<int,5> ret;
for(int i(0); i<5; i++) {
if(appt[i]==ans[i]) ret[i]=2;
else ret[i]=0;
}
for(int i(0); i<5; i++) if(!ret[i]) {
for(int j(0); j<5; j++) {
if(ret[j]!=2 && appt[i]==ans[j]) { ret[i]=1; break; }
}
}
return ret;
}
int to_num(std::array<int,5> result) {
int p(1);
int ret(0);
for(int i(0); i<5; i++) ret+=result[i]*p, p*=3;
return ret;
}
int cnt[243];
const char *guess(int num_testcase, int remaining_guesses, char initial_letter, bool *gold, bool *silver) {
if(remaining_guesses==5) {
st.clear();
for(int i(0); i<n; i++) {
if(table[i][0]==initial_letter) st.push_back(table[i]);
}
las=ans_fir[initial_letter-'a'];
return las.data();
} else {
int result[5];
for(int i(0); i<5; i++) result[i]=std::max(gold[i]*2, (int)silver[i]);
std::vector<std::string> nxt;
for(auto i : st) {
std::array<int,5> now(check(las, i));
bool flg(1);
for(int j(0); j<5; j++) {
if(gold[j]*2+silver[j]!=now[j]) { flg=0; break; }
}
if(flg) nxt.push_back(i);
}
st=nxt;
siz=st.size();
long double max(-1);
for(int i(0); i<n; i++) {
for(int j(0); j<243; j++) cnt[j]=0;
for(auto j : st) cnt[to_num(check(table[i], j))]++;
long double p(0);
for(int i(0); i<243; i++) {
long double x((long double)cnt[i]/siz);
if(x==0) continue;
p+=-x*log2(x);
}
p+=0.01*cnt[242]/siz;
if(p>max) max=p, las=table[i];
}
return las.data();
}
}