Rainbow_qwq
2021-04-14 18:10:21
感谢神仙 _MoonPie_
给的这个题 ,终于会这题做法了。
首先我们有
然后还要在剩下的 50+ 次询问中找出正确答案。
如果现在不确定区间为
那么询问一次
这样的话:
可以使用上面那个 高楼扔鸡蛋 问题的第二个 dp 做法来找答案。
这个
设
设分界点
(如果不懂这个转移,可以看上面那个知乎链接)
于是每次询问点在 dp 中也就确定了。可以在
最后还有那个前面提到的“调整钱数”,官方题解说调整的询问次数
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define int long long
using namespace std;
inline int read()
{
char c=getchar();int x=0;bool f=0;
for(;!isdigit(c);c=getchar())f^=!(c^45);
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
if(f)x=-x;return x;
}
int askcnt,now,qaq,MX=1e14;
inline int ask(int x){
if(x>MX){
return 0;
}
askcnt++;
if(qaq){
if(x<=qaq)return now+=x,1;
else return now-=x,0;
}
cout<<"? "<<x<<endl;
string s;cin>>s;
if(s=="Lucky!")return now+=x,1;
return now-=x,0;
}
bool vis[105][105];
int dp[105][105];
void work()
{
int l=1,r=1e14;
now=1,askcnt=0;
if(!ask(1)){
cout<<"! 0"<<endl;
return;
}
while(1){
int k=now;
if(ask(k))l=k;
else{r=k-1;break;}
}
now=0;
ask(l);
int x=1,y=(now>=r);
while(dp[x][y]<=r-l) x++;
while(l<=r)
{
while(r-l>dp[x][y])
ask(l-1),++y;
int mid=l+dp[x-1][y-1];
while(now<mid) ask(l-1);
if(ask(mid)) ++y,--x,l=mid+1;
else --x,--y,r=mid-1;
}
cout<<"! "<<l-1<<endl;
if(qaq)printf("x=%lld cnt=%lld\n",qaq,askcnt);
}
int F(int x,int y)
{
if(vis[x][y])return dp[x][y];
vis[x][y]=1;
if(x==0)return 0;
if(y==0)return dp[x][y]=dp[x-1][1];
return dp[x][y]=F(x-1,y+1)+1+F(x-1,y-1);
}
signed main()
{
// x=0 dp(0,y)=0
// y=0 dp(x,0)=dp(x-1,1)
For(x,0,50)
For(y,0,x)
F(x,y);
// qaq=99999999999808;
int T=read();
while(T--)work();
return 0;
}