SPOJ GUESSN4 Guess The Number With Lies v4

来源:互联网 发布:js define是什么意思 编辑:程序博客网 时间:2024/05/16 10:21

GUESSN4 Judge has chosen an integer x in the range [1, n]. Your task
is to find x, using at most m queries as described below. But be
careful, because there are 2 important things:
1. The Judge can lie. Judge is allowed to lie only once in single game and only in reply for query.
2. You must prepare all queries at once and send all of them to the Judge before You got any reply. Query Single query should contains
string s1s2s3…sn, where si is ‘0’ or ‘1’. The reply for query is
“YES”, if sx = ‘1’, or “NO” otherwise. For example, when n=8, x=5 and
query is “00101011”, the Judge will reply “YES” (if telling the truth)
or “NO” (if lying), because the 5th character in query is ‘1’. Real
task and scoring The real task is not to find the number x chosen by
Judge, but only to prepare queries, which allow You to guess the x
value for every possible Judge’s reply. The Judge won’t give You reply
for Your queries. If the Judge will find such reply for Your queries,
that there will be more than one x value possible, You will fail the
test case (see example for detail explanation). Otherwise You succeed.
If You succeed, Your score is q2, where q is the number of queries,
that You use. If You fail, You got penalty score equal to 4m2. Total
score is the sum of scores of single games. The smaller score is the
better score. Input The first line of input contains one integer T -
the number of test cases. Then T test cases follow. Each test case
contains one line with two single-space separated integers n and m,
where n is the size of the game and m is the maximal number of
queries, that You can use. Output For each test case print a line with
one integer q - the number of queries that You want to ask. Then print
q lines with Your queries. Each query should be string of length n,
with all characters ‘0’ or ‘1’. Constraints 1 ≤ T ≤ 27 2 ≤ n ≤ 216 3
⌈log2 n⌉ ≤ m 0 ≤ q ≤ m For bigger tests, number of test cases is
smaller (T ≤ 40 for 10000 ≤ m ≤ 20000, T ≤ 20 for 20000 ≤ n ≤ 30000, T
≤ 10 for 30000 ≤ n)

如果不能说谎的话很简单,对于每一位为1的分别询问。
如果能说谎,最简单的方法是每个问题提三遍,这样某一个与其他两个不一样的回答就是谎言。需要3log2n次询问,恰好是题目给的范围,就可以AC了。

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;char s[1000000];int main(){    int T,n,m,i,j,k;    scanf("%d",&T);    while (T--)    {        scanf("%d%d",&n,&m);        for (k=0;(1<<k)<n;k++);        printf("%d\n",3*k);        for (i=0;(1<<i)<n;i++)        {            for (j=0;j<n;j++)                s[j]=((j>>i)&1)+'0';            s[n]=0;            for (j=1;j<=3;j++) printf("%s\n",s);        }    }}

但是还可以更优,需要转换角度。
考虑成需要传输一个01串,其中有至多一位会出错。需要给出能纠错的传输方案。刚才的方法就相当于把这个串传输三遍。
可以只传输两遍,然后设置奇偶校验位【1的个数是奇还是偶】一起传输。如果两遍不同则根据奇偶校验位确定答案。具体做法就是把所有询问异或一下。询问次数2log2n+1

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<bitset>using namespace std;bitset<70000> b,b1;int main(){    int T,n,m,i,j,k;    scanf("%d",&T);    while (T--)    {        scanf("%d%d",&n,&m);        for (k=0;(1<<k)<n;k++);        printf("%d\n",2*k+1);        b.reset();        for (i=0;(1<<i)<n;i++)        {            for (j=0;j<n;j++)                b1[j]=(j>>i)&1;            for (k=1;k<=2;k++)            {                for (j=0;j<n;j++) putchar(b1[j]+'0');                putchar('\n');            }            b^=b1;        }        for (j=0;j<n;j++) putchar(b[j]+'0');        putchar('\n');    }}

还可以还可以做到更好,只传输一遍,然后仿照最开始的思路,对每一位为1的设置奇偶校验。但是这样会有问题,即2的整数次幂只在某一位被校验,无法判断是原串出错还是校验位出错。所以再加一个所有询问的奇偶校验。
注意编号的细节,对原数一定要看成0..n1,否则在n2的整数次幂而且比较小的时候压不到3log2n。但是这里对询问编号要从1开始,否则0无法校验。
这个做法在SPOJ上RANK3,前两名可能采用的是汉明码,但是差别很小。

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<bitset>using namespace std;bitset<70000> b,b1,b2[25];int main(){    int T,n,m,i,j,n1,n2;    scanf("%d",&T);    while (T--)    {        scanf("%d%d",&n,&m);        for (n1=0;(1<<n1)<n;n1++);        for (n2=0;(1<<n2)<=n1;n2++);        printf("%d\n",n1+n2+1);        b.reset();        for (i=0;i<n2;i++) b2[i].reset();        for (i=0;i<n1;i++)        {            for (j=0;j<n;j++)            {                b1[j]=(j>>i)&1;                putchar(b1[j]+'0');            }            putchar('\n');            for (j=0;j<n2;j++)                if ((i+1>>j)&1)                    b2[j]^=b1;            b^=b1;        }        for (i=0;i<n2;i++)        {            for (j=0;j<n;j++)                putchar(b2[i][j]+'0');            putchar('\n');        }        for (j=0;j<n;j++) putchar(b[j]+'0');        putchar('\n');    }}
0 0
原创粉丝点击