zoukankan      html  css  js  c++  java
  • CF1483E Vabank 题解

    Codeforces
    Luogu
    Solution Link

    Description.

    猜数,需要猜出 \(M(M\in[1,10^14])\),有一个权值 \(P\) 初始是 \(1\)
    你每次可以询问一个数 \(X\),分以下三种情况讨论。

    • \(X\le M\),返回 Lucky!\(P\leftarrow P+X\)
    • \(P\ge X>M\),返回 Fraudster!\(P\leftarrow P-X\)
    • \(X>M,X>P\),直接 Wrong Answer

    交互次数 \(105\) 次。

    Solution.

    首先你可以用 \(\log\) 次查询得到 \(X\in[2^k,2^{k+1})\),此后 \(P=2^k-1\)
    查询过程是直接另 \(X=2^k\)\(P=2^{k+1}-1\)
    这两步肯定无法优化,而且已经想到了。
    关键问题在与得知了 \([L,R]\) 怎么用 \(60\) 步左右求出 \(X\)

    首先有一个 \(2\log V\) 的做法,就是每次查询前查一次 \(L\),防止 \(P<X\)
    但是总复杂度是 \(3\log V \approx 138\),不行。
    当然可以用把 \(2\log V\) 变成 \(2\log_{e}V\approx 110\),超了一点。
    说明这个东西卡的很紧,应该需要最优决策。

    考虑你如果查询了一个 \(X\in[L,R]\),你可以获得什么:
    有一种思路就是尝试“铤而走险”,尝试利用 \(X\le M\) 不需要 \(X\le P\) 的性质。
    但是这个思路肯定行不通,因为肯定可以被卡。

    1. \(X\le M\),这样 \(P\leftarrow P+X\),有 \(P\ge R-L+(k+1)L\),就可以调整 \(P\ge R-(X+1)+(k+1)(X+1)\),后来区间是 \([X+1,R]\)
    2. \(P\ge X\ge M\),这样 \(P\leftarrow P-X\),有 \(P\ge R-L+(k-1)L\),后来区间是 \([L,X-1]\)

    所以 \(P\) 可以被表示成 \(R-L+wL\),1 就 \(k\leftarrow k+1\),2 就 \(k\leftarrow k-1\)
    这样就考虑到经典的面试问题——测鸡蛋硬度问题。
    设计一个 dp 表示第当前还能抛 \(K\) 次,还有 \(w\) 个“鸡蛋”的方案数。
    考虑 1 就相当于扔一次多了一个鸡蛋(怪),2 就碎了一个鸡蛋。
    然后就有 \(dp_{K,w}=dp_{K-1,w+1}+dp_{K-1,w-1}+1\)
    每次抛这个分界点,就可以知道最优决策了。

    至于调整复杂度,和 Sjy 一样不会证明。

    注意需要特判问的数超过 \(10^{14}\) 的情况!!!

    Coding.

    点击查看代码
    //Coded by leapfrog on 2021.11.04 {{{
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    ll M,P=1,dp[55][105],debug;
    inline char Ask(ll X)
    {
    #ifdef ONLINE_JUDGE
    	if(X>100000000000000) return 0;
    	printf("? %lld\n",X),fflush(stdout);char ch[15];
    	scanf("%s",ch);if(ch[1]=='i') exit(0);
    	if(*ch=='L') return P+=X,1;else return P-=X,0;
    #else
    	debug++;
    	if(X<=M) return P+=X,1;else if(X>M&&P>=X) return P-=X,0;
    	puts("OH NO your quertion is wrong!"),exit(0);
    #endif
    }
    inline void Ans(ll x)
    {
    #ifdef ONLINE_JUDGE
    	printf("! %lld\n",x),fflush(stdout);
    #else
    	if(x==M) puts("Accepted!");else puts("Wrong Answer /ll");
    	printf("totally used %lld asks\n",debug);
    #endif
    }
    inline void solve()
    {
    #ifndef ONLINE_JUDGE
    	read(M),debug=0;
    #endif
    	ll l=1,r=1e14,rs=0;P=1;if(!Ask(1)) return Ans(0);
    	for(ll tp=0,v=1;(0^v^0);) if(Ask(tp=P)) l=tp;else {r=tp-1;break;}
    	Ask(l);int k=1,w=(P>=r);while(dp[k][w]<=r-l) k++;
    	while(l<=r)
    	{
    		while(r-l>dp[k][w]) Ask(l-1),w++;
    		ll md=l+(w?dp[k-1][w-1]:0);while(P<md) Ask(l-1);
    		if(Ask(md)) k--,w++,l=md+1,rs=md;else r=md-1,k--,w--;
    	}Ans(rs);
    }
    inline void init()
    {
    	for(int i=1;i<=50;i++) for(int j=0;j<=100;j++)
    		dp[i][j]=(dp[i-1][j+1]+(j?dp[i-1][j-1]+1:0));
    }
    int main() {int Ca;for(init(),read(Ca);Ca--;) solve();return 0;}
    
  • 相关阅读:
    浏览器—CORS 通信的学习总结
    前端算法
    移动端适配时对meta name="viewport" content="width=device-width,initial-scale=1.0"的理解
    react和vue的区别
    对xss攻击和csrf攻击的理解
    前端如何解决跨域
    你没那么重要
    五福
    天道
    决策
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15510244.html
Copyright © 2011-2022 走看看