LG10384
一道相当不错的概率题。
首先考虑种子中存在 \(\verb!aa!\) 的情况。显然,我们可以让每个不是 \(\verb!aa!\) 的种子都与这个 \(\verb!aa!\) 型的种子杂交,并检验杂交后的性状。若为 \(\verb!a!\),则一定为 \(\verb!Aa!\),否则可能是 \(\verb!AA!\) 或 \(\verb!Aa!\)。不难想到多杂交几次,如果一直都显现出 \(\verb!A!\) 则可以认为就是 \(\verb!AA!\)。取杂交次数为 \(15\) 次时,错误率在 \(2^{-15}\) 左右,完全可以接受。
如果种子中不存在 \(\verb!aa!\),这样做不能够保证正确性。换一种思路想,对于给定的任意两颗种子,其可能的情况有 \(\{ \verb!AA!,\verb!AA! \},\{ \verb!AA!,\verb!Aa! \},\{ \verb!Aa!,\verb!AA! \},\{ \verb!Aa!,\verb!Aa! \}\) 四种。第四种情况最好检验,有 \(\frac{1}{4}\) 的概率出现 \(\verb!a!\),而别的情况则不可能出现,因此做多几次杂交即可判断这种情况。
对于剩下的三种情况,继续分类讨论。显然,如果是 \(\{ \verb!AA!\ ,\verb!AA! \}\),无论如何杂交都是 \(\verb!AA!\)。但如果是 \(\{ \verb!AA!\ ,\verb!Aa! \}\) 或 \(\{ \verb!Aa!\ ,\verb!AA! \}\),其子代中很大概率有 \(\verb!Aa!\) 的出现。又由于两个亲代中一定有一个 \(\verb!Aa!\),因此可能杂交出 \(\verb!aa!\)。如果出现了 \(\verb!aa!\),则可以证明上述的情况。如果所有子代与亲代杂交都没有 \(\verb!aa!\),则可以认为亲本都是 \(\verb!AA!\)。又因为 \(15 \times 3 \times 10^4 = 4.5\times 10^5\),因此杂交 \(15\) 次是较为合适的。此时的错误率也较低,交多几次就可以通过了。
如果杂交次数过多而无法通过,可以考虑一个简单的优化:如果当前已经杂交出了 \(\verb!aa!\),则对剩余的种子可以直接用文章最前面的方法判断即可。
#include <bits/stdc++.h>
using namespace std;
char query(int k);
void cross(int i, int j);
int a[1000001];
vector<string> guess(int n)
{
srand( time( 0 ) );
vector<string> ans;
int cnt = n,tot = 0,d = 0,flag,lst;
char c;
for( int i = 1 ; i <= n ; i ++ )
{
c = query( i );
if( c == 'a' )
{
a[i] = 3;
if( !d ) d = i;
}
}
if( d )
{
for( int i = 1 ; i <= n ; i ++ )
{
if( a[i] == 3 ) continue;
flag = 0;
for( int t = 1 ; t <= 15 ; t ++ )
{
cnt ++;
cross( i , d );
if( query( cnt ) == 'a' )
{
flag = 1;
break;
}
}
if( flag ) a[i] = 2;
else a[i] = 1;
}
for( int i = 1 ; i <= n ; i ++ )
{
if( a[i] == 1 ) ans.push_back( "AA" );
if( a[i] == 2 ) ans.push_back( "Aa" );
if( a[i] == 3 ) ans.push_back( "aa" );
}
return ans;
}
int i;
for( i = 1 ; i <= n && !d ; i += 2 )
{
lst = cnt;
for( int t = 1 ; t <= 14 && !d ; t ++ )
{
cnt ++;
cross( i , i + 1 );
if( query( cnt ) == 'a' )
{
d = cnt;
a[i] = 2,a[i + 1] = 2;
break;
}
}
for( int t = 1 ; t <= 14 && !d ; t ++ )
{
cnt ++;
cross( lst + t , i );
if( query( cnt ) == 'a' )
{
d = cnt;
a[i] = 2;
break;
}
cnt ++;
cross( lst + t , i + 1 );
if( query( cnt ) == 'a' )
{
a[i + 1] = 2;
d = cnt;
break;
}
}
if( !a[i] ) a[i] = 1;
if( !a[i + 1] ) a[i + 1] = 1;
}
for( ; i <= n ; i ++ )
{
flag = 0;
for( int t = 1 ; t <= 14 ; t ++ )
{
cnt ++;
cross( i , d );
if( query( cnt ) == 'a' )
{
flag = 1;
break;
}
}
if( flag ) a[i] = 2;
else a[i] = 1;
}
for( int i = 1 ; i <= n ; i ++ )
{
if( a[i] == 1 ) ans.push_back( "AA" );
if( a[i] == 2 ) ans.push_back( "Aa" );
if( a[i] == 3 ) ans.push_back( "aa" );
}
return ans;
}