分析
Subtask1
在某个物品旁边放上一个蓝色石子,这样子 Koala 就只能得到至多 $99$ 个物品,而没选的那个物品一定是权值最小的。
这样子只需要调用一次 playRound
,可以得到 $4$ 分。
Subtask2
先在每个物品旁边放 $1$ 个蓝色石子,这样子 Koala 会选出至多 $50$ 个物品,所以我们可以确定权值前 $50$ 大的物品。
那么可以再在这 $50$ 个物品中每个旁边放 $2$ 个蓝色石子,套一下交互库可以发现这时确定了权值前 $25$ 大的物品。
再在这 $25$ 个物品中每个旁边放 $4$ 个蓝色石子,再套一下交互库可以发现这时确定了权值前 $9$ 大的物品。
再在这 $9$ 个物品中每个旁边放 $11$ 个蓝色石子,这样子就确定了权值最大的物品了。
这样子需要调用四次 playRound
,可以得到 $15$ 分。
Subtask3
可以想到在 $0$ 和 $1$ 旁边各放 $w$ 个蓝色石子,如果 Koala 恰好只选择了其中的一个的话我们就知道哪个大了。所以关键在于找出这个 $w$。
可以考虑二分,上界是 $13$,因为再大的话 $0$ 和 $1$ 都不会选。
如果写 r=mid / l=mid+1
的话需要调用四次 playRound
,可以得到 $14$ 分;但是这里可以写 r=mid-1 / l=mid+1
,所以只需要调用三次 playRound
,可以得到 $18$ 分。
Subtask4
考虑如何比较两个物品的权值的大小。可以在两个物品旁边各放 $100$ 个蓝色石子,这样子 Koala 只会选其中一个,就可以通过调用一次 playRound
比出来了。
于是直接排序即可。用 std::sort
可以得到 $0$ 分,用 std::stable_sort
可以得到 $10$ 分。
Subtask5
一个想法是把 Subtask3 和 Subtask4 缝合在一起,用 std::sort
可以得到约 $24$ 分,用 std::stable_sort
可以得到约 $29$ 分。
考虑对值域分治,每层维护值域在 $[l,r]$ 内的位置集合,在 $l=r$ 时直接赋值即可。
问题在于如何划分。我们需要找到一个 $w$,满足在值域为 $[l,r]$ 的这些位置旁各放 $w$ 个蓝色石子后 Koala 只会得到其中的一部分。假设有 $k$ 个没有得到,则可以划分为 $[l,l+k-1]$ 和 $[l+k,r]$。
因为数据范围很小,所以可以枚举这个 $w$,只要想办法判断是否合法即可。可以跑个背包(可以直接蒯交互库)求出 Koala 在每个物品旁边放的红色石子个数,就可以很方便的判断了。
因为每个分治区间只需要调用一次 playRound
,所以总共只需要调用 $99$ 次,可以得到 $53$ 分。
Subtask0
样例没有 AC 怎么办?打表即可。
代码
这是 LOJ AC 代码,要在洛谷上过需要自己改一下格式。
// ====================================
// author: M_sea
// website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#include "koala.h"
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
using namespace std;
typedef long long ll;
const int N=100+10;
// Subtask1
int minValue(int n,int w) {
if (n==6) return 3;
static int a[N],b[N]; memset(a,0,sizeof(a));
a[0]=1; playRound(a,b);
for (int i=0;i<n;++i)
if (b[i]<=a[i]) return i;
}
// Subtask2
int maxValue(int n,int w) {
if (n==6) return 4;
static int a[N],b[N];
for (int i=0;i<n;++i) a[i]=1;
playRound(a,b);
for (int i=0;i<n;++i) a[i]=b[i]>1?2:0;
playRound(a,b);
for (int i=0;i<n;++i) a[i]=b[i]>2?4:0;
playRound(a,b);
for (int i=0;i<n;++i) a[i]=b[i]>4?11:0;
playRound(a,b);
for (int i=0;i<n;++i) if (b[i]>11) return i;
}
// Subtask3
int greaterValue(int n,int w) {
if (n==6) return 0;
static int a[N],b[N]; memset(a,0,sizeof(a));
int L=1,R=13;
while (L<R) {
int mid=(L+R)>>1;
a[0]=a[1]=mid; playRound(a,b);
if (b[0]>mid&&b[1]<=mid) return 0;
if (b[0]<=mid&&b[1]>mid) return 1;
if (b[0]<=mid) R=mid-1;
else L=mid+1;
}
}
// Subtask4
bool cmp(int x,int y) {
static int a[N],b[N]; memset(a,0,sizeof(a));
a[x]=a[y]=100; playRound(a,b);
return b[x]<b[y];
}
// Subtask5
bool check(int w,int l,int r) {
static int a[N],b[N]; memset(a,0,sizeof(a));
for (int i=l-1;i<=r-1;++i) a[i]=w;
static int c[2][N],n[2][N],f[N][N];
memset(c[1],0,sizeof(c[1]));
memset(n[1],0,sizeof(n[1]));
memset(f,0,sizeof(f));
for (int i=0;i<100;++i) {
int v=a[i]+1;
int now=i&1,pre=now^1;
memcpy(c[now],c[pre],sizeof(c[now]));
memcpy(n[now],n[pre],sizeof(n[now]));
for (int j=100;j>=v;--j) {
int h=c[pre][j-v]+i;
int hn=n[pre][j-v]+1;
if (h>c[now][j]||(h==c[now][j]&&hn>n[now][j]))
c[now][j]=h,n[now][j]=hn,f[i][j]=1;
else f[i][j]=0;
}
}
for (int cur=100,i=99;~i;--i)
b[i]=f[i][cur]?a[i]+1:0,cur-=b[i];
for (int i=l;i<=r-1;++i) if (b[i]!=b[l-1]) return 1;
return 0;
}
int getval(int l,int r) {
for (int i=0;i<=100/(r-l+1);++i)
if (check(i,l,r)) return i;
}
void solve(int l,int r,vector<int> pos,int* p) {
if (l==r) { p[pos[0]]=l; return; }
static int a[N],b[N]; memset(a,0,sizeof(a));
int w=getval(l,r);
for (int i:pos) a[i]=w;
playRound(a,b);
vector<int> L,R;
for (int i:pos) {
if (b[i]<=a[i]) L.emplace_back(i);
else R.emplace_back(i);
}
solve(l,l+(int)L.size()-1,L,p),solve(l+(int)L.size(),r,R,p);
}
void allValues(int n,int w,int* p) {
if (n==6) {
p[0]=5,p[1]=3,p[2]=2,p[3]=1,p[4]=6,p[5]=4;
return;
}
if (w==200) {
static int q[N];
for (int i=0;i<n;++i) q[i]=i;
stable_sort(q,q+n,cmp);
for (int i=0;i<n;++i) p[q[i]]=i+1;
} else {
vector<int> pos;
for (int i=0;i<n;++i) pos.emplace_back(i);
solve(1,n,pos,p);
}
}