[NOI2024] 百万富翁
[NOI2024] 百万富翁
交互题给到 NOI。
题意
初始时交互库有一个 \(1\) 到 \(n\) 的排列 \(p\)。你可以进行若干轮请求,每轮请求中包含若干个查询。每个查询形如一个二元组 \((i,j)\),若 \(p_i > p_j\) 则返回 \(i\),否则返回 \(j\)。你需要找出排列中最大元素的下标。
交互库自适应,记你进行的请求轮数为 \(T\),你给出的查询个数为 \(S\)。
子任务 \(1\):\(n=1000\),要求 \(T \leq 1\),\(S \leq 499500\)。
子任务 \(2\):\(n=1000000\),要求 \(T \leq 8\),\(S \leq 1099944\)。
思路
我们发现,在 \(1\) 轮请求中,想要确定 \(t\) 个位置中的最大元素最少需要 \(f(t)=\dfrac{t(t-1)}{2}\) 个查询。这也是子任务 \(1\) 的做法。
接下来我们考虑子任务 \(2\)。假设当前有 \(a\) 个位置要找出最大值。我们考虑将其划分为 \(b\) 组,则其中有 \(a \bmod b\) 组有 \(\lfloor \dfrac{a}{b} \rfloor + 1\) 个位置,有 \(b - (a \bmod b)\) 组有 \(\lfloor \dfrac{a}{b} \rfloor\) 个位置。那么此时从 \(a\) 个位置中挑出 \(b\) 个需要的询问组数 \(g(a,b)=(a \bmod b) \times f(\lfloor \dfrac{a}{b} \rfloor + 1) + (b-(a \bmod b)) \times f(\lfloor \dfrac{a}{b} \rfloor)\)。
我们的目标就是需要求出一个长度为 \(9\) 的序列 \(L\),满足 \(L_1=1000000\),\(L_9=1\),\(\sum_{i=1}^{8}g(L_i,L_{i+1}) \leq 1099944\)。
在考场上,我们可以选择等暴力或写模拟退火。总之可以得到一组满足要求的 \(L=\{1000000,500000,250000,125000,62496,20832,3472,183,1\}\)。然后直接模拟即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include "richest.h"
using namespace std;
int L[9]={1000000,500000,250000,125000,62496,20832,3472,183,1};
int cnt[1000000];
int richest(int N,int T,int S){
vector<int> list_a,list_b;
if(N==1000){
for(int u=0;u<N;u++){
for(int v=u+1;v<N;v++){
list_a.push_back(u);
list_b.push_back(v);
}
}
vector<int> list_c=ask(list_a,list_b);
for(int i=0;i<N;i++){
cnt[i]=0;
}
int tmp=-1,maxn=-1;
for(int k=0;k<list_c.size();k++){
cnt[list_c[k]]++;
if(cnt[list_c[k]]>=maxn){
maxn=cnt[list_c[k]];
tmp=list_c[k];
}
}
return tmp;
}
else{
vector<int> list_id;
for(int i=0;i<N;i++){
list_id.push_back(i);
}
for(int T=0;T<8;T++){
vector<int> num;
list_a.clear();
list_b.clear();
int tot=-1;
for(int j=0;j<L[T+1];j++){
if(j<L[T]%L[T+1]){
int l=tot+1;
int r=tot+L[T]/L[T+1]+1;
int cnt=0;
for(int u=l;u<r;u++){
for(int v=u+1;v<=r;v++){
list_a.push_back(list_id[u]);
list_b.push_back(list_id[v]);
cnt++;
}
}
tot=r;
num.push_back(cnt);
}
else{
int l=tot+1;
int r=tot+L[T]/L[T+1];
int cnt=0;
for(int u=l;u<r;u++){
for(int v=u+1;v<=r;v++){
list_a.push_back(list_id[u]);
list_b.push_back(list_id[v]);
cnt++;
}
}
tot=r;
num.push_back(cnt);
}
}
vector<int> list_c=ask(list_a,list_b);
list_id.clear();
for(int i=0;i<N;i++){
cnt[i]=0;
}
tot=0;
for(int j=0;j<L[T+1];j++){
int tmp=-1,maxn=-1;
for(int k=tot;k<tot+num[j];k++){
cnt[list_c[k]]++;
if(cnt[list_c[k]]>=maxn){
maxn=cnt[list_c[k]];
tmp=list_c[k];
}
}
list_id.push_back(tmp);
tot=tot+num[j];
}
}
return list_id[0];
}
}

浙公网安备 33010602011771号