[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];
	}
}
posted @ 2025-06-01 23:19  Oken喵~  阅读(2)  评论(0)    收藏  举报