Luogu

LOJ

分析

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);
    }
}
最后修改:2020 年 08 月 11 日 07 : 42 PM