P10384「HOI R1」杂交选种 题解
挺好玩的一个题。
我们知道,要测定基因型,最好的办法是测交,也就是拿 aa 和它去杂交,这样我们就可以开始分讨:
先对所有种子进行一个 query ;
-
如果其中有 \(\mathtt{aa}\) 基因型,就拿它和所有 \(\mathtt{AA}\)/\(\mathtt{Aa}\) 种子都杂交 \(k\) 遍, 如果子代中有 \(\mathtt{aa}\) 基因型那么它就是 \(\mathtt{Aa}\) ,反之即为 \(\mathtt{AA}\)。这样做对于每一个种子成功的概率都是 \(1-(\frac{1}{2})^k\) ,\(k\) 取最大值 \(22\) 时,全部成功的概率大约是 \(99.52\%\) 。
-
反之,我们对种子两两分组分别杂交 \(k_1\) 次。
- 对于 \(\mathtt{\{Aa,Aa\}}\) , 如果子代中出现了 \(\mathtt{aa}\) , 那么就可以直接按照第一种方式判定,正确的概率为 \(1-(\frac{3}{4})^{k_1}\) , 然后再对每一个基因型测交 \(k_2\) 次,正确的概率是 \((1-(\frac{1}{2})^{k_2})^n\), 当 \(k_1\) 取 \(8\) 时,这个概率是 \(83.4\%\) 。
- 如果没有 \(\mathtt{\{Aa,Aa\}}\) 的话,我们就需要判断其中的 \(\mathtt{\{AA,Aa\}}\) 和 \(\mathtt{\{Aa,AA\}}\) 并用 \(\mathtt{aa}\) 测交。即对于每一个种子,将它们与所有自己的子代杂交,当 \(k_2\) 取 \(18\) 且当前基因型为 \(\mathtt{Aa}\) 时,自己的子代中期望有 \(9\) 个是 \(\mathtt{Aa}\),即成功的概率为 \((1-(\frac{3}{4})^9)=0.92\) ;判断出 \(\mathtt{Aa}\) 后我们手上现在也有了一个 \(\mathtt{aa}\) 再次使用第一种方式即可,正确的概率是 \(84.6\%\) 。
其实 \(15\) 个点要使用此方法均通过的话,最劣情况成功概率只有 \(0.834^{15} = 0.066\) , 但是这个概率估算并不准确,还有比如说 2.1 中即使有 \(\mathtt{Aa}\) 误判了,也有后面的兜底。 所以真实的成功概率其实要高不少。
如果没过的话多交几遍,我赛时交了两遍。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+5;
char query(int k);
void cross(int i,int j);
string hete="Aa",rece="aa",phen="AA";
vector<string> vc;
vector<string> ans;
bitset<N> flag;
int fst[N];
vector<string> guess(int n){
vc.push_back(rece);
int arece=0,now=n,flag=0;
for(int i=1;i<=n;i++){
vc.push_back(phen);
if(query(i)=='a')vc[i]=rece,arece=i;
}
if(!arece){
for(int i=1;i<=n;i+=2){
fst[i]=fst[i+1]=now;
for(int j=1;j<=8;j++){
cross(i,i+1);
++now;
if(query(now)=='a'){
arece=now;
flag=1;
break;
}
}
if(flag)break;
}
if(arece){
for(int i=1;i<=n;i++){
for(int j=1;j<=18;j++){
cross(arece,i);
++now;
if(query(now)=='a'){
vc[i]=hete;
break;
}
}
}
}else{
for(int i=1;i<=n;i++){
if(!arece){
for(int j=1;j<=18;j++){
cross(i,fst[i]+(j-1)%12+1);
++now;
if(query(now)=='a'){
arece=now;
vc[i]=hete;
break;
}
}
}else{
for(int j=1;j<=18;j++){
cross(i,arece);
++now;
if(query(now)=='a'){
vc[i]=hete;
break;
}
}
}
}
}
}else{
for(int i=1;i<=n;i++){
if(vc[i]==rece)continue;
int y=0;
for(int j=1;j<=22;j++){
cross(i,arece);
now++;
y+=(query(now)=='a');
}
if(y)vc[i]=hete;
}
}
for(int i=1;i<=n;i++)ans.push_back(vc[i]);
return ans;
}
//int main(){return 0;}