spoj GUESSN2 Guess The Number With Lies v2

GUESSN2

Judge has chosen an integer x in the range [1, n]. Your task is to
find x, using query as described below. But be careful, because the
Judge is a liar. Judge is allowed to lie up to w times in single game
and only in reply for query. Query

Single query should contains set S = {a1, a2, …, ak}. The reply for
query is “YES”, if x is in S. Otherwise the reply is “NO”.

1 ≤ k < n

1 ≤ a1 < a2 < … < ak ≤ n Communication

You should communicate with Judge using standard input and output.

Attention: the program should clear the output buffer after printing
each line. It can be done using fflush(stdout) command or by setting
the proper type of buffering at the beginning of the execution -
setlinebuf(stdout).

The first line of input contains single integer T, the number of
games. Then T games follow.

At the beggining of each game You should send to the Judge a line with
command “START_GAME”. The Judge will answer You with numbers n, w, m,
where n, w are as described above and m is the maximum number of
queries that You can use in this game.

Then You should send some queries, every query is a line with “QUERY”
keyword, then single-space separated values k a1 a2 … ak. After each
query the Judge will answer “YES” or “NO”.

At the end of game You should give answer: “ANSWER y”, where 0 ≤ y ≤
n; y=0 means, that You skip this game without the correct answer.
Otherwise y is the answer for the game. When y ≠ x, the solution will
got WA.

Then start the next game (if there is any). Scoring

Total score is the sum of scores of single games. If You use c queries
in game and You find the x value, Your score is c2. If You skip the
game, the score is 4m2. The smaller score is the better score.
Constraints

1 ≤ T ≤ 27

2 ≤ n ≤ 217

2 ≤ w ≤ 24

1 ≤ w * n ≤ 219

定义 f[i] 表示如果答案是 i ,还能撒谎几次。当前状态不确定性的估价函数为ni=1f[i]j=0Cjm,其中 w 表示还能撒谎几次,m表示还能询问几次。直观含义就是枚举哪几次撒谎。
这样,每一步就尽量要缩小该估价函数。因为交互机足够聪明,所以应该让回答“Yes”或“No”后新的估价函数尽可能相等【也就是均分】。对于每个元素问或者不问,回答有还是没有对新的估价函数的贡献的差值是 Cf[i]m 【其中 m <script type="math/tex" id="MathJax-Element-473">m</script>是这一步操作之后剩下的】。因此就转化成了一个要把若干个数均分成相等的两个集合的问题。可以从大到小排序以后贪心。虽然不能保证最优,但是效果还可以。

#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-8;
vector<int> q1,q2;
pair<double,int> a[200010];
int f[200010];
double c[1010][1010];
void init()
{
    for (int i=0;i<=1000;i++) c[i][0]=1;
    for (int i=1;i<=1000;i++)
        for (int j=1;j<=i;j++)
            c[i][j]=c[i-1][j-1]+c[i-1][j];
}
bool cmp(pair<double,int> p1,pair<double,int> p2)
{
    return p1.first>p2.first+eps;
}
void solve()
{
    int n,m,w,num,ans;
    double v1,v2;
    char s[5];
    printf("START_GAME\n");
    fflush(stdout);
    scanf("%d%d%d",&n,&w,&m);
    for (int i=1;i<=n;i++) f[i]=w;
    while (m--)
    {
        num=0;
        for (int i=1;i<=n;i++)
            if (f[i]>=0)
                a[++num]=make_pair(c[m][f[i]],i);
        sort(a+1,a+num+1,cmp);
        v1=v2=0;
        q1.clear();
        q2.clear();
        for (int i=1;i<=num;i++)
            if (v1+eps<v2||(fabs(v1-v2)<eps&&(i&1)))
            {
                v1+=a[i].first;
                q1.push_back(a[i].second);
            }
            else
            {
                v2+=a[i].first;
                q2.push_back(a[i].second);
            }
        sort(q1.begin(),q1.end()); 
        printf("QUERY %d",q1.size());
        fflush(stdout);
        for (int i=0;i<q1.size();i++)
        {
            printf(" %d",q1[i]);
            fflush(stdout);
        }
        printf("\n");
        fflush(stdout);
        scanf("%s",s);
        if (s[0]=='Y') for (int i=0;i<q2.size();i++) f[q2[i]]--;
        else for (int i=0;i<q1.size();i++) f[q1[i]]--;
        ans=0;
        for (int i=1;i<=n;i++)
            if (f[i]>=0)
            {
                if (ans) ans=-1;
                else ans=i;
            }
        if (ans>0)
        {
            printf("ANSWER %d\n",ans);
            fflush(stdout);
            return;
        }
    }
    printf("ANSWER 0\n");
    fflush(stdout);
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值