题解:P17142 [NOI 2026] 布丁(暂无数据)
写一个官解没有的随机化做法。
我们问一个已经排好序的序列
我们发现最大质因子
具体地,我们每次随机从满足上面的序列中随机几个,维护目前可能的答案集合,挑选信息熵最大的进行询问即可。
思路非常简单,这个做法写出来的代码不经过任何调参即可获得五十多分,经过一些调参可获得
下面放出代码,已在 qoj 通过。
#include<bits/stdc++.h>
#include"pudding.h"
#define rep(i, j, k) for(int i=(j); i<=(k); ++i)
#define per(i, j, k) for(int i=(j); i>=(k); --i)
#define siz(x) (int)x.size()
using namespace std;
using vec=vector<int>;
vec&operator+=(vec&a,int x){return a.emplace_back(x), a;}
vec operator+(vec a, int x){return a+=x;}
vec&operator+=(vec&a,vec b){for(auto x:b) a+=x; return a;}
vec operator+(vec a, vec b){return a+=b;}
const int N=6003, V=3000, M=1e6+5;
int tot, dep[N], sum[N];
vec q[N], d[N];
map<int, int> son[N];
vector<vec> pq[10];
int sd=311153493;
mt19937 rnd(sd);
int ri(int l, int r){return uniform_int_distribution<int>(l, r)(rnd);}
int len[3]={10, 10, 8};
int cnt[3]={(int)(1e4), (int)(2e4), (int)(2e4)};
int gcd(int x, int y){
int zx=__builtin_ctz(x), zy=__builtin_ctz(y), z=min(zx, zy);
x>>=zx, y>>=zy;
while(x!=y){
if(x<y) swap(x, y);
x-=y;
x>>=__builtin_ctz(x);
}
return x<<z;
}
int calc(vec d){
per(i, siz(d)-2, 0)
if(d[i]>d[i+1]) swap(d[i], d[i+1]);
else break;
int w=0;
rep(i, 0, siz(d)-2)
w+=gcd(d[i], d[i+1]);
return w;
}
int calc(const vec &q, const vec &d){
int mx=1;
static int vis[M], t, cnt[M];
++t;
int w=0;
rep(i, 0, siz(q)-2) w+=gcd(q[i], q[i+1]);
int p=0;
for(auto x:d){
int v=w;
if(x<q.front()) v+=gcd(x, q.front());
else if(x>q.back()) v+=gcd(x, q.back());
else{
while(q[p+1]<x) ++p;
v+=gcd(q[p], x)+gcd(q[p+1], x)-gcd(q[p], q[p+1]);
}
if(vis[v]!=t) vis[v]=t, cnt[v]=1;
else ++cnt[v], mx=max(mx, cnt[v]);
}
return mx;
}
void init(int c, int t){
tot=1;
if(c==1){
rep(i, 1, 35) d[1]+=i;
}
else if(c==2){
auto prime=[&](int x)->bool {
for(int i=2; i*i<=x; i++) if(x%i==0) return 0;
return 1;
};
rep(i, 1, V) if(prime(i)) d[1]+=i;
}
else{
rep(i, 1, V) d[1]+=i;
}
vec pr{2, 3, 5, 7, 11, 13};
vec num;
auto ck=[&](int x)->bool {
for(auto p:pr) while(x%p==0) x/=p;
return x==1;
};
rep(i, 1, 4500) if(ck(i)) num+=i;
rep(u, 1, tot) if(siz(d[u])>1){
int best=1e9;
int Z=dep[u];
if(dep[u]==3 || siz(d[u])<=len[Z]){
q[u]=d[u];
}
else{
for(int i=0; i<=cnt[Z] || best>=siz(d[u]); i++){
vec z;
if(i<pq[Z].size()){
z=pq[Z][i];
}
else if(i<=cnt[Z]/2){
rep(i, 1, len[Z]) z+=num[ri(0, siz(num)-1)];
sort(z.begin(), z.end());
} else{
z=q[u];
rep(_, 1, 5) z[ri(0, siz(z)-1)]=num[ri(0, siz(num)-1)];
sort(z.begin(), z.end());
}
int tmp=calc(z, d[u]);
if(tmp<best){
best=tmp;
q[u]=z;
}
}
unordered_set<int> s;
rep(i, 0, siz(q[u])-2)
s.emplace(gcd(q[u][i], q[u][i+1]));
}
sum[u]+=siz(q[u]);
pq[Z].emplace_back(q[u]);
for(auto x:d[u]){
int tmp=calc(q[u]+x);
int v;
if(son[u].count(tmp)) v=son[u][tmp];
else son[u][tmp]=v=++tot, dep[v]=dep[u]+1, sum[v]=sum[u];
d[v]+=x;
}
}
}
int find_tastiness(int c, int m){
int u=1;
while(siz(d[u])>1){
int z=query_tastiness(q[u]);
assert(son[u].count(z));
u=son[u][z];
}
return d[u][0];
}