题解 P5208 【[WC2019]I 君的商店】
P5208 【[WC2019]I 君的商店】
第一次过交互题,可能也是我退役之前过的唯一一道交互题了。
为了方便叙述,令物品
sub 1,2,4,5
首先,我们可以先得出两个显然的结论:
-
如果
v_b\le v_c 且v_a\ge v_b+v_c ,则我们可以直接推出v_b=0 ,对于任意a,b,c 成立(否则v_b=v_c=1,v_b+v_c=2>1\ge v_a ,矛盾)。 -
如果
v_b\le v_c 且v_a\le v_b+v_c ,则我们可以直接推出v_a\le v_c ,对于任意a,b,c 成立(否则v_a=1,v_b=v_c=0,v_b+v_c=0<1=v_a ,矛盾)。特别的,如果已知v_a=1 ,则可以据此确定v_c=1 。
然后我们发现,如果我们能够确定一个数
而确定一个
而由于这个物品的价格大于等于所有其他物品的价格,且题目保证一定存在
然后我们再根据上述的两个结论,每次任取两个数
如果
最后我们会发现只剩一个数没法比较。但由于题目给定了奇偶性,所以我们可以根据目前的
在找
但我们发现如果使用这种做法,想要再减少
sub3
在这个子任务中,我们看到了一个很好的性质:价值是单调递增(递减)的。我们可以很显然的想到使用二分。
首先,我们可以通过判断
我们依然考虑采用前面的方法,将两个数和
由于序列一定存在一个
我们设
二分处那一个
应该说思路非常简单,但代码实现却有一点难度,稍有不慎就会写错。
我的写法是设
if(n<=2||sub==3){
for(int i=0;i<n;i++){
o[i]=i;
}
if(leq(0,n-1)){
reverse(o,o+n);
}
int l=0,r=n-1;
while(l<r){
int mid=l+r+1>>1;
if(mid<n-1&&leq(o[0],o[mid],o[mid+1])){
l=mid;
}
else{
r=mid-1;
}
}
ans[o[l+1]]=(l+1^k)&1;
for(int i=0;i<=l;i++){
ans[o[i]]=1;
}
return;
}
sub6
受到 sub3 的做法的启发,我们可以考虑构造一个单调递增的序列,然后用这个在这个序列上进行二分。恰好数据范围多给了
每次,我们选取
每次先比较
如果
否则我们可以推出
举个例子,
然后
然后
接着我们发现,数组中的上一个数正好是
然后接下来如果有数进来,那一定是
于是我们就发现这个数组是按照价值单调递增的。
最后我们会剩下两个数,其中一个是
由于此时的
然后我们比一次,就能比出一个较大者(设为
然后我们仿照 sub3 二分,直到数组中只剩一个数(设为
然后我们就只剩
好像思路还挺简单的
贴个代码,调了半天的(
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+6;
int tmp[2][2];
int o[maxn],cnt;
int query(int *S,int nS,int *T,int nT);
bool leq(int a,int b){
tmp[0][0]=a;tmp[1][0]=b;
return query(tmp[0],1,tmp[1],1);
}//return a<b
bool leq(int a,int b,int c){
tmp[0][0]=a;tmp[1][0]=b;tmp[1][1]=c;
return query(tmp[0],1,tmp[1],2);
}//return a<b+c
void find_price(int sub,int n,int k,int ans[]){
cnt=0;
if(n<=2||sub==3){
for(int i=0;i<n;i++){
o[i]=i;
}
if(leq(0,n-1)){
reverse(o,o+n);
}
int l=0,r=n-1;
while(l<r){
int mid=l+r+1>>1;
if(mid<n-1&&leq(o[0],o[mid],o[mid+1])){
l=mid;
}
else{
r=mid-1;
}
}
ans[o[l+1]]=(l+1^k)&1;
for(int i=0;i<=l;i++){
ans[o[i]]=1;
}
return;
}
int a,b,c;
a=0,c=1;
for(int i=2;i<n;i++){
b=i;
if(leq(c,b)){
swap(b,c);
}
if(leq(a,b,c)){
o[cnt++]=a;
a=c;c=b;
}
else{
ans[b]=0;
}
}
if(leq(c,a)){
swap(a,c);
}
ans[c]=1;
if(!cnt){
ans[a]=k^1;
return;
}
o[cnt++]=c;
int l=0,r=cnt-1;
reverse(o,o+cnt);
while(l<r){
int mid=l+r+1>>1;
if(mid<cnt-1&&leq(o[0],o[mid],o[mid+1])){
l=mid;
}
else{
r=mid-1;
}
}
for(int i=0;i<=l;i++){
ans[o[i]]=1;
}//o[l+1] 和 a 未知
c=o[l+1];
if(leq(c,a)){
swap(a,c);
}
if(leq(o[0],c,a)){
ans[c]=1;
l++;
}
else{
ans[a]=0;
a=c;
}
ans[a]=(l+1^k)&1;
return;
}