题解:CF2108D Needle in a Numstack
include13_fAKe · · 题解
中考前最后一场 CF(指的是我回归文化课以前的最后一场)的好题。
拖得也有个半年了。
首先不难发现
首先询问
考虑二分得到
总询问次数
#include<bits/stdc++.h>
#define int long long
#define mp(a,b) make_pair(a,b)
using namespace std;
inline int read(){
int a=0,b=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-') b=-1;
c=getchar();
}
while(isdigit(c)){
a=(a<<1)+(a<<3)+(c-'0');
c=getchar();
}
return a*b;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>=10) write(x/10);
putchar(x%10+48);
}
inline void write1(int x){
write(x),putchar(' ');
}
inline void write2(int x){
write(x),putchar('\n');
}
//似乎是一个 4k+log n 的做法,记录一下
const int N=460;
const int M=1919810;
int query[N];
int query1[N];
int ans[M];
//int sol[N]; //代表哪些位置是我们可以去处理的
int sol_first;
int sol_lst; //代表与 sol_first 相对的值
int n,k;
int idx;
int sum_; // 节数
void solve(){
idx=0;
sol_first=1e18;
n=read(),k=read();
sum_=n/k +(n%k!=0);
if(n==k*2){
putchar('!'),putchar(' '),write1(k),write2(k);
fflush(stdout);
return;
}
for(int i=n-k+1;i<=n;i++){
//现在查询的
putchar('?'),putchar(' '),write2(i);
fflush(stdout);
query[++idx]=i;
query1[idx]=read();
ans[i]=query1[idx];
int j=i%k;
if(j==0) j=k;
putchar('?'),putchar(' '),write2(j);
fflush(stdout);
query[++idx]=j;
query1[idx]=read();
ans[j]=query1[idx];
if(ans[i]!=ans[j]){
if(sol_first>j){
sol_first=j;
sol_lst=i;
}
}
}
if(sol_first>1e16){
putchar('!'),putchar(' '),write2(-1);
fflush(stdout);
return;//无法确定
}
int l=1,r=(sol_lst-sol_first)/k+1;
int mid=l+r>>1;
while(l<r){
int now=(mid-1)*k+sol_first; //代表目前的位置
putchar('?'),putchar(' '),write2(now);
fflush(stdout);
query[++idx]=now;
query1[idx]=read();
ans[now]=query1[idx];
if(ans[now]==ans[sol_first]) l=mid+1;
else r=mid;
mid=l+r>>1;
}
// cout<<'#'<<mid<<endl;
//现在用了 2k+log 次询问
mid=(mid-1)*k+sol_first; //代表目前所在的位置
int max_left=k,min_right=n-k+1; //如果 max_left 和 min_right 之间存在值 就为 -1
for(int i=min(mid+k,n-k);i>=max(k,mid-k);i--){
//判断所有的位置和前后是否相关
int l=i%k;
int r=l+sum_*k;
if(l==0) l=k;
while(r>n) r-=k;
if(ans[l]==ans[r]) continue; //说明这里进行询问没有意义
putchar('?'),putchar(' '),write2(i);
fflush(stdout);
query[++idx]=i;
query1[idx]=read();
ans[i]=query1[idx];
if(ans[i]==ans[l]){
//代表这里是左翼的
max_left=max(max_left,i);
}
else{
//右翼
min_right=min(min_right,i);
}
}
if(max_left==min_right-1){
putchar('!'),putchar(' '),write1(max_left),write2(n-max_left);
fflush(stdout);
}
else{
putchar('!'),putchar(' '),write2(-1);
fflush(stdout);
}
for(int i=1;i<=idx;i++){
ans[query[i]]=0;
query[i]=0;
query1[i]=0;
}
idx=0;
}
#undef int
int main(){
#define int long long
int T=read();
while(T--) solve();
putchar('\n');
return 0;
} //一定要挽回罗琪钧的遗憾啊,一定会挽回罗琪钧的遗憾的!