2019雅礼集训 D11T3 字符串 [交互题]

Posted p-b-p-b

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019雅礼集训 D11T3 字符串 [交互题]相关的知识,希望对你有一定的参考价值。

题目描述:

技术分享图片

技术分享图片

技术分享图片

guess.h:

#include<string>
int query(int l,int r);
std::string guess();

grader.cpp:

#include"guess.h"
#include<string>
#include<stdio.h>
#include<iostream> 
using namespace std;
typedef unsigned long long u64;
static struct random_t{
    u64 s0,s1;
    random_t(){s0=2,s1=3;}
    random_t(u64 s0,u64 s1):s0(s0),s1(s1){}
    u64 get(){
        std::swap(s0,s1);
        s1^=s1<<23,s1^=(s1>>17)^s0^(s0>>26);
        return s0+s1;
    }
    int randint(int L,int R){
        return get()%(R-L+1)+L;
    }
}rnd;
static const int N=1000,M=N+5;
static string S;
static int cnt[M],qcnt;
static bool asked[M][M];
void ensure(bool True,const char *Message){
    if(!True){
        printf("%s
",Message);
        exit(-1);
    }
}
int query(int l,int r){
    ensure(l<=r,"Invalid Query: not a range");
    ensure(0<=l&&r<N,"Invalid Query: index out of range");
    ensure(!asked[l][r],"Invalid Query: asked before");
    ++qcnt,asked[l][r]=true;
    if(rnd.randint(0,1))return cnt[r+1]-cnt[l];
    int res=rnd.randint(0,r-l);
    return res+(res>=cnt[r+1]-cnt[l]);
}
int main(){
    int Test;
    for(cin>>Test;Test;--Test){
        cin>>S;
        for(int i=0;i<N;++i)ensure(S[i]==‘0‘||S[i]==‘1‘,"Invalid Input");
        ensure(S.length()==N,"Invalid Input");
        cin>>rnd.s0>>rnd.s1; 
        for(int i=0;i<N;++i)cnt[i+1]=(S[i]==‘1‘)+cnt[i];
        ensure(guess()==S,"Wrong Answer");
        printf("Accepted Answer: %d queries used",qcnt);
    }
}

思考如何得到一个区间的1的个数:每次询问只有一半的可能得到正确的答案,但多询问几次(尽管每个区间只能被询问1次,但区间可以被截一刀变成两个区间查询两次),取答案的众数,得到正确答案的可能性就会变大。

那么如何得到一个点(x)的数字呢?(sum_{[l,x]}-sum_{[l,x-1]})即可。

于是我们对于每个(x)可以询问几次取众数,答案就出来了。有不错的分数。

考虑优化:显然查询的区间越大,错误答案就会越分散,造成的影响就越小。那么我们前500个位置向后查询,后500个向前查询,查询的次数就可以降低。

继续优化:剁成两个区间后分别查询,正确率会降至(frac{1}{4})。可以先乱搞出前50个位置的答案,后边在前面剁一刀,就只需要查询一次了,正确率重新回到(frac{1}{2})

具体的查询次数等参考题解:

技术分享图片

懒得写,放标程:

#include "guess.h"
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
using u64 = unsigned long long;
using pii = pair<int, int>;
const int N = 1000, B = 50, T = 40;
struct random_t {
    u64 s0, s1;
    random_t(){
        s0 = size_t(new char) xor time(nullptr); 
        s1 = size_t(new char) xor (s0 + time(nullptr));
    }
    random_t(u64 s0, u64 s1):s0(s0), s1(s1){}
    u64 get(){
        std::swap(s0, s1);
        s1 ^= s1 << 23, s1 ^= (s1 >> 17) ^ s0 ^ (s0 >> 26);
        return s0 + s1;
    }
    int randint(int L, int R){
        return get() % (R - L + 1) + L;
    }
} rnd;
int ans[N + 5][N + 5], lsum[N + 5], rsum[N + 5], sum;
map<pii, int> os;
int _query(int l, int r){
    if (l > r) return 0;
    if (os.count(pii(--l, --r))) return os[pii(l, r)];
    return os[pii(l, r)] = query(l, r);
}
int calc(int l, int r, int L, int R){
    int x, v, mx, mv;
    map<int, int> cnt;
    vector<int> ff;
    for (x = -(T >> 1); x < (T + 1) >> 1; ++x) ff.pb(((l + r) >> 1) + x);
    for (v = 0; v < ff.size(); ++v) swap(ff[v], ff[rnd.randint(1, ff.size()) - 1]);
    for (int y : ff) {
        v = _query(l, y) + _query(y + 1, r);
        if (v < L || v > R) continue;
        if (++cnt[v] >= 4) return v;
    }
    mv = 0;
    for (auto it : cnt) if (mv < it.second) mx = it.first, mv = it.second;
    return mx;
}
int calc_pre(int x, int a, int b){
    int ca = 0, cb = 0, v;
    vector<int> ff;
    for (v = 1; v <= B; ++v) ff.pb(v);
    for (v = 0; v < ff.size(); ++v) swap(ff[v], ff[rnd.randint(1, ff.size()) - 1]);
    for (int y : ff) {
        v = lsum[y] + _query(y + 1, x);
        if (v == a) ++ca;
        if (v == b) ++cb;
        if (ca >= cb + 2) return a;
        if (cb >= ca + 2) return b;
    }
    throw "GG";
}
int calc_suf(int x, int a, int b){
    int ca = 0, cb = 0, v;
    vector<int> ff;
    for (v = 0; v < B; ++v) ff.pb(N - v);
    for (v = 0; v < ff.size(); ++v) swap(ff[v], ff[rnd.randint(1, ff.size()) - 1]);
    for (int y : ff) {
        v = _query(x, y - 1) + rsum[y];
        if (v == a) ++ca;
        if (v == b) ++cb;
        if (ca >= cb + 2) return a;
        if (cb >= ca + 2) return b;
    }
    throw "GG";
}
string guess(){
    int x;
    string res;
    memset(ans, -1, sizeof(ans)), memset(lsum, 0, sizeof(lsum)), memset(rsum, 0, sizeof(rsum)), sum = 0, os.clear();
    try {
        rsum[1] = lsum[N] = sum = calc(1, N, 0, N);
        for (x = 1; x <= B; ++x) rsum[x + 1] = calc(x + 1, N, rsum[x] - 1, rsum[x]), lsum[x] = sum - rsum[x + 1];
        for (x = N; x > N / 2; --x) lsum[x - 1] = calc_pre(x - 1, lsum[x] - 1, lsum[x]), rsum[x] = sum - lsum[x - 1];
        for (x = B + 1; x <= N / 2; ++x) rsum[x + 1] = calc_suf(x + 1, rsum[x] - 1, rsum[x]), lsum[x] = sum - rsum[x + 1];
        for (x = 1; x <= N; ++x) res += lsum[x] - lsum[x - 1] + ‘0‘;
    } catch(const char *v) {
        for (res = "", x = 1; x <= N; ++x) res += ‘0‘;
    }
    return res;
}

以上是关于2019雅礼集训 D11T3 字符串 [交互题]的主要内容,如果未能解决你的问题,请参考以下文章

2019雅礼集训 D4T1 w [费用流]

2019雅礼集训 D7T3 convex [咕咕咕]

2019雅礼集训 D8T1 union [咕咕咕]

[2018雅礼集训1-16]方阵

2019雅礼集训 D10T1 数字重排 [DP]

2019雅礼集训 D8T3 union [主席树]