結果

問題 No.624 Santa Claus and The Last Dungeon
ユーザー rickythetarickytheta
提出日時 2017-12-24 12:06:56
言語 C++11
(gcc 11.4.0)
結果
AC  
実行時間 40 ms / 2,000 ms
コード長 4,216 bytes
コンパイル時間 1,451 ms
コンパイル使用メモリ 167,452 KB
実行使用メモリ 25,496 KB
平均クエリ数 374.17
最終ジャッジ日時 2024-07-16 15:10:28
合計ジャッジ時間 4,745 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 40 ms
24,824 KB
testcase_01 AC 37 ms
25,208 KB
testcase_02 AC 37 ms
25,196 KB
testcase_03 AC 36 ms
25,208 KB
testcase_04 AC 37 ms
24,952 KB
testcase_05 AC 35 ms
25,208 KB
testcase_06 AC 36 ms
24,952 KB
testcase_07 AC 37 ms
24,568 KB
testcase_08 AC 37 ms
24,568 KB
testcase_09 AC 37 ms
24,952 KB
testcase_10 AC 37 ms
24,952 KB
testcase_11 AC 39 ms
25,208 KB
testcase_12 AC 39 ms
24,568 KB
testcase_13 AC 36 ms
24,568 KB
testcase_14 AC 37 ms
24,952 KB
testcase_15 AC 38 ms
25,208 KB
testcase_16 AC 37 ms
24,568 KB
testcase_17 AC 38 ms
24,568 KB
testcase_18 AC 37 ms
25,208 KB
testcase_19 AC 37 ms
24,952 KB
testcase_20 AC 37 ms
24,568 KB
testcase_21 AC 40 ms
24,568 KB
testcase_22 AC 38 ms
25,208 KB
testcase_23 AC 39 ms
24,824 KB
testcase_24 AC 37 ms
24,824 KB
testcase_25 AC 39 ms
24,952 KB
testcase_26 AC 39 ms
24,824 KB
testcase_27 AC 38 ms
25,208 KB
testcase_28 AC 39 ms
25,496 KB
testcase_29 AC 37 ms
25,208 KB
testcase_30 AC 39 ms
24,824 KB
testcase_31 AC 38 ms
24,928 KB
testcase_32 AC 37 ms
24,824 KB
testcase_33 AC 37 ms
24,824 KB
testcase_34 AC 38 ms
25,208 KB
testcase_35 AC 37 ms
24,952 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
main.cpp: In function ‘void query()’:
main.cpp:50:8: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
   50 |   scanf("%d%d%d",&p0,&p1,&p2);
      |   ~~~~~^~~~~~~~~~~~~~~~~~~~~~
main.cpp: In function ‘int main()’:
main.cpp:160:8: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
  160 |   scanf("%d%d%d",&p0,&p1,&p2);
      |   ~~~~~^~~~~~~~~~~~~~~~~~~~~~

ソースコード

diff #

/*
想定解より削れるので一応解説

Q=550の方針、つまり分割統治までは同じで、片方の桁は大体260回ぐらいで終わるとします
問題はQ=450のところで、18回期待値で10個確定できるのって結構非自明じゃないですか?
だってlog_2(10!)って22ぐらいじゃないですか
ということを唸っていたら、以下の方針を思いつきました。

やりたいことは想定解とほとんど同じで、10個のブロックを1つ1つ確定させていきます。
ただし上述の理由で少し心もとないので、暗号の結果を2桁一致まで教えてくれることを利用して2倍の短縮をします。
片方のブロックについては1つの桁のみを使ってクエリを投げて(使わない桁は?を埋める)、
もう片方のブロックについてはすでに分かっている桁も合わせて2桁でクエリを投げます。
すると、後者については2桁一致が見つかればそれがそのまま見つかった数に一致して、
前者についてはそれも踏まえた上で1桁一致の数を数えれば結果を知ることが出来ます。
よってかなりクエリ回数に余裕が出てきます。

2桁まで教えてくれるって言うから絶対これが想定解だな〜〜〜賢いなぁ〜〜〜
とか思ってたら期待値ゲーが想定だったというオチ(なんだそのオチ)
*/

#include <bits/stdc++.h>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define FORR(i,a,b) for(int i=(int)(b)-1;i>=(int)(a);i--)

typedef long long ll;
typedef vector<int> vi;

int perm[125];
int revperm[125];

char s[353];
int p0, p1, p2;
void clear(){
  REP(i,100){
    s[3*i] = s[3*i+1] = '?';
    s[3*i+2] = ' ';
  }
  s[299] = '\0';
}
void setval(int p, int u, int d){
  p = perm[p];
  s[3*p+0] = u==-1 ? '?' : '0'+u;
  s[3*p+1] = d==-1 ? '?' : '0'+d;
}
void query(){
  puts(s);fflush(stdout);
  scanf("%d%d%d",&p0,&p1,&p2);
}

int u[125];
int d[125];

void solve_d(vi cand, int rest, int val){
  if(cand.size() == rest){
    // all ok
    REP(i,cand.size()){
      d[cand[i]] = val;
    }
    return;
  }
  if(rest == 0){
    return;
  }
  // split into 2 segment
  int m = cand.size() / 2;
  clear();
  REP(i,m)setval(cand[i], -1, val);
  query();
  vi va, vb;
  REP(i,m)va.push_back(cand[i]);
  FOR(i,m,cand.size())vb.push_back(cand[i]);
  int x = p1;
  int y = rest-p1;
  solve_d(va, x, val);
  solve_d(vb, y, val);
}

void dfs_u(vi ca, vi cb, vi va, vi vb){
  if(ca.size() == 1){
    u[ca[0]] = va[0];
    u[cb[0]] = vb[0];
    return;
  }
  int n = ca.size();
  vi lca, rca, lcb, rcb, lva, rva, lvb, rvb;
  REP(i,n/2){
    lca.push_back(ca[i]);
    lcb.push_back(cb[i]);
  }
  FOR(i,n/2,n){
    rca.push_back(ca[i]);
    rcb.push_back(cb[i]);
  }
  REP(i,n-1){
    int a = va[i];
    int b = vb[i];
    clear();
    REP(j,lca.size()){
      setval(lca[j], a, -1);
      setval(lcb[j], b, d[lcb[j]]);
    }
    query();
    int x = p1, y = p2;
    if(y==1){
      // b in left
      lvb.push_back(b);
      x++;
    }else{
      rvb.push_back(b);
    }
    if(x==lca.size()+1){
      // a in left
      lva.push_back(a);
    }else{
      rva.push_back(a);
    }
  }
  (lva.size()==lca.size() ? rva : lva).push_back(va.back());
  (lvb.size()==lcb.size() ? rvb : lvb).push_back(vb.back());
  dfs_u(lca, lcb, lva, lvb);
  dfs_u(rca, rcb, rva, rvb);
}

void solve_u(int a, int b){
  vi ca, cb;
  REP(i,100){
    if(d[i]==a)ca.push_back(i);
    if(d[i]==b)cb.push_back(i);
  }
  vi va, vb;
  REP(i,10)va.push_back(i);
  REP(i,10)vb.push_back(i);
  dfs_u(ca, cb, va, vb);
}

int main(){
  int q;cin>>q;
  REP(i,100)u[i] = d[i] = -1;
  // randomize
  srand(time(NULL));
  REP(i,100)perm[i] = i;
  random_shuffle(perm, perm+100);
  REP(i,100)revperm[perm[i]] = i;
  // solve for d
  REP(i,10){
    vi cand;
    REP(j,100)if(d[j]==-1)cand.push_back(j);
    solve_d(cand, 10, i);
  }
  // solve for u
  REP(i,5){
    solve_u(2*i, 2*i+1);
  }
  // ok
  REP(i,100)printf("%d%d%c",u[revperm[i]],d[revperm[i]],i==99?'\n':' ');
  fflush(stdout);
  scanf("%d%d%d",&p0,&p1,&p2);
  return 0;
}
0