「BalticOI 2021 Day1」A Difficult Choice
「BalticOI 2021 Day1」A Difficult Choice
题目大意
这是一道交互题,有一个长度为 \(n\) 且未知的正整数序列 \(a_i\),保证其单调递增。
你可以用任意顺序询问其中至多 \(S\) 个数,并且对于给定的阈值 \(A\) 和大小 \(k\),要求从 \(n\) 个数中选出 \(k\) 个数(不能重复),使得它们的和 \(\in [A,2A]\)。
分析
-
先取前 \(k-1\) 个,然后二分找到序列中最后一个 \(i\) ,使得 \(a_1+a_2+\cdots+a_{k-1} +a_i\leq 2A\)。
-
如果不存在这样的 \(i\) 则无解。
-
如果找到的这样的和恰好 \(\ge A\),则找到一组解。
-
否则,如果存在解则一定可以用 \([1,k-1]\) 和 \([i-k+1,i]\) 中的数得到一组解。
次数为 \(\log n+2k-2\)。
#include<bits/stdc++.h>
#include "books.h"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int,int> Pii;
#define reg register
#define mp make_pair
#define pb push_back
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
void solve(int n,int k,ll L,int m) {
static const int N=1e6+10;
assert(m>=40);
if(k>n) return impossible();
static ll a[N];
rep(i,1,n) a[i]=-1;
ll s=0;
rep(i,1,k-1) s+=a[i]=skim(i);
if(s>2*L) return impossible();
int l=k,r=n,res=-1;
while(l<=r) {
int mid=(l+r)>>1;
a[mid]=skim(mid);
if(s+a[mid]>=L && s+a[mid]<=2*L) {
vector <int> t;
rep(i,1,k-1) t.pb(i);
t.pb(mid);
return answer(t);
}
if(s+a[mid]>2*L) r=mid-1;
else l=mid+1,res=mid;
}
if(res==-1) return impossible();
if(a[k]==-1) a[k]=skim(k);
rep(i,max(k+1,res-k+1),res) if(a[i]==-1) a[i]=skim(i);
static int pos[N],c=0;
rep(i,1,res) if(~a[i] && (i<=k || i>res-k)) pos[c++]=i;
rep(S,0,(1<<c)-1) if(__builtin_popcount(S)==k) {
ll v=0;
rep(i,0,c-1) if(S&(1<<i)) v+=a[pos[i]];
if(v>=L && v<=2*L) {
vector <int> t;
rep(i,0,c-1) if(S&(1<<i)) t.pb(pos[i]);
return answer(t);
}
}
return impossible();
}