P10786 [NOI2024] 百万富翁

因为交互库是自适应的,所以当你只进行一次请求时,必须使得两两之间都有联系,也就是形成一个团才能正确。
对于 \(N=1000000\),很容易想到一个 \(\log N\) 次请求的做法:两两分组连边,这样查询次数只有 \(n+O(1)\) 次,但是显然过不去。
所以我们可以考虑适当增加查询次数,将分组大小改为 \(B\),也就是划分成若干个大小为 \(B\) 的团连边,最后剩下一个 \(cnt\bmod B\) 的团(\(cnt\) 为可能为最大值的个数),略调一下参可以获得79分。
我们发现这个过程是可以 dp 的,所以稍微限制一下团的大小,暴力打表可以获得82分,但还不够。
考虑策略的缺陷,可能是因为 \(B\nmid cnt\),于是最后剩余的团的连边不优。所以可以考虑增加另一种团 \(B2\),同一个请求便可以采用两种团,于是暴力枚举 \(B,B2\) 大小以及 \(B\) 的个数dp转移打表,花上 700s 就可以得到题目要求的界了!(实际上好像可以钦定 \(B2=B+1\))。
代码:

#include<bits/stdc++.h>
using namespace std;
//#include"richest.h"
std::vector<int> ask(std::vector<int> a, std::vector<int> b);
const int M=1e6+5;
using ll=long long;
int n;
bool uns[M];
int gt[M];
mt19937 rnd(time(0));
int LIM;
int ori[21]={2,2,2,2,4,7,18,183,55,3,3,3,3,3,3,3,3,3,3,3};
int ori2[21]={0,0,0,0,3,6,19,0,0};
int num[21]={0,0,0,0,1,1,4,0,0};
int richest(int N,int T,int S){
	vector<int>a,b,c,cur;LIM=1099944;
	memset(uns,0,sizeof uns);
	int cnt=0;
	if(N==1000){
		for(int i=0;i<N;i++){
			for(int j=i+1;j<N;j++)a.push_back(i),b.push_back(j);
		}
		c=ask(a,b);
		for(int i=0;i<N;i++)for(int j=i+1;j<N;j++)(c[cnt++]==i)?uns[j]=1:uns[i]=1;
		for(int i=0;i<N;i++)if(!uns[i])return i;
	}
	for(int i=0;i<21;i++){
		cur.clear();a.clear();b.clear();
		for(int j=0;j<N;j++)if(!uns[j])cur.push_back(j);
		if((int)(cur.size())==1)return cur[0];
		int B=ori[i];
		int len=cur.size();B=min(B,len);
		if(1ll*len*(len-1)/2<=LIM){
			for(int j=0;j<len;j++){
				for(int k=j+1;k<len;k++){
					a.push_back(cur[j]),b.push_back(cur[k]);
				}
			}
			LIM=0;
		}
		int pcnt=0;
		for(int j=0;j<len&&LIM;j+=B){
			pcnt++;
			int ss=min(len-j,B);
			for(int k=0;k<ss;k++){
				for(int l=k+1;l<ss&&LIM;l++){
					a.push_back(cur[j+k]),b.push_back(cur[j+l]);
					LIM--;
				}
			}
			if(pcnt==num[i])j+=B,B=ori2[i],j-=B;
		}
		c=ask(a,b);
		cnt=c.size();
		for(int j=0;j<cnt;j++)(c[j]==a[j])?uns[b[j]]=1:uns[a[j]]=1;
	}
	return 1;
}

打表程序:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
using ll=long long;
int n,a[N];
auto *it=new unsigned;
mt19937 rnd(time(0)^(*it));
inline int mr(int l,int r){return rnd()%(r-l+1)+l;}
unordered_map<int,int>um[N];
int cnt;
bool vis[N];
int gt[N];
ll dp[N][23];
int pre[N][23],pre2[N][23],num[N][23];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T;
//	cin>>T;
	dp[1][0]=0;
	for(int i=1;i<=8;i++)dp[1][i]=1e18;
	for(int i=2;i<=1e6;i++){
		for(int k=0;k<=8;k++)dp[i][k]=1e18;
		for(int k=1;k<=min(i,8);k++){
			int x=1;
			for(int j=2;j<=min(200,i);j++){
				if((i/j)*j*(j-1)/2>dp[i][k])break;
				int s=i%j;
				ll cur=dp[i/j+(s?1:0)][k-1]+1ll*s*(s-1)/2+(i/j)*(1ll*j*(j-1)/2);
				if(cur<dp[i][k]){
					dp[i][k]=cur;
					pre[i][k]=j;
				}
			}
			for(int j=2;j<=min(30,i);j++){
				for(int l=2;l<=min(30,i);l++){
					for(int thr=1;thr<=min(i/j,30);thr++){
						int ps=(i-j*thr);
						int s=ps%l;
						ll cur=dp[thr+ps/l+(s?1:0)][k-1]+s*(s-1)/2+thr*(j*(j-1)/2)+ps/l*l*(l-1)/2;
						if(cur<dp[i][k]){
							dp[i][k]=cur;
							pre[i][k]=j;
							num[i][k]=thr,pre2[i][k]=l;
						}
					}
					
				}
			}
		}
		if(i<=500){
			for(int k=1;k<=8;k++){
				cerr<<i<<" "<<k<<" "<<dp[i][k]<<" "<<pre[i][k]<<"???\n";
			}
		}
		if(i%100==0)cerr<<i<<"??\n";
	}
	int cur=1e6;
	int k=8;
	while(cur>1){
		int s=pre[cur][k];
		if(!num[cur][k])cerr<<cur<<" "<<s<<"???\n",cur=cur/s+((cur%s)?1:0);
		else cerr<<cur<<" "<<pre[cur][k]<<" "<<pre2[cur][k]<<" "<<num[cur][k]<<"???\n",cur=num[cur][k]+(cur-num[cur][k]*pre[cur][k])/pre2[cur][k]+((cur-num[cur][k]*pre[cur][k])%pre2[cur][k]?1:0);
		k--;
	}
	cerr<<dp[1000000][8]<<"GHG\n";
	T=1;
	for(int i=1;i<=30;i++){
		cout<<(162-i)*(161-i)/2-(4129-13*i)<<"???\n";
	}
//	while(T--)solve();
	return 0;
}
posted @ 2025-03-22 22:17  wjwweiwei  阅读(59)  评论(0)    收藏  举报