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;
}

浙公网安备 33010602011771号