P17142 [NOI 2026] 布丁
对第一步爬山,不用加任何剪枝,估价为划分出等价类大小最大值,每次加一个数删一个数。在 \(len=10\) 时容易搞出 \(\max=84\) 的解,当然多跑一会可以更小。q2s94。
初始取 \(len=9\),可以先爬山出来 \(\max=80\) 的解。然后对每个等价类分别退火,钦定选 \(6\) 个数,等几分钟就有 \(q=3,s\le30\) 的解,直接打表就好。q3s29。
稍微精细一点,把次数多的等价类拉出来单独一个个退火,每个多跑一下,跑不出来可以改一下集合大小。q3s26。
upd:最后一次把所有数都问一遍,这里可以把最大值删掉,可以再少一次。q3s25。
退火代码
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
template <typename T>
bool Chkmax(T &x, T y) { return (x < y) ? (x = y, 1) : 0; }
template <typename T>
bool Chkmin(T &x, T y) { return (x > y) ? (x = y, 1) : 0; }
mt19937_64 gen (random_device{} ());
int rnd(int l, int r) {
return uniform_int_distribution<> (l, r) (gen);
}
double rd() {
return uniform_real_distribution<> (0, 1) (gen);
}
const int kN = 9005;
int n, m, V, type, mn = inf, mx;
int g[kN][kN];
bitset<kN> can;
int num[kN], tot[kN];
bool in[kN];
vector<int> all;
vector<int> vec, ans;
bool IsPrime(int x) {
if(x <= 1) return 0;
for(int i = 2; i * i <= x; i++) {
if(!(x % i)) return 0;
}
return 1;
}
int D(int x) {
int d = 0;
for(int i = 1; i * i <= x; i++) {
if(!(x % i)) {
d += 2 - (i * i == x);
}
}
return d;
}
int New() { return rnd(1, V); }
void Upd(int x, int v) {
x += V;
tot[num[x]]--;
tot[num[x] += v]++;
if(tot[mx + 1]) mx++;
else if(!tot[mx]) mx--;
}
void UpdSeg(int l, int r, int v) {
for(int i = can._Find_next(l); i < r; i = can._Find_next(i)) {
Upd(g[l][i] + g[r][i] - g[l][r], v);
}
}
void Ins(int x) {
in[x] = 1;
auto it = lower_bound(vec.begin(), vec.end(), x);
int l = *prev(it), r = *it;
UpdSeg(l, x, 1);
UpdSeg(x, r, 1);
if(can[x]) Upd(x, 1);
UpdSeg(l, r, -1);
vec.insert(it, x);
}
void Era(int x) {
in[x] = 0;
auto it = lower_bound(vec.begin(), vec.end(), x);
int l = *prev(it), r = *next(it);
UpdSeg(l, r, 1);
UpdSeg(l, x, -1);
UpdSeg(x, r, -1);
if(can[x]) Upd(x, -1);
vec.erase(it);
}
void SA() {
const double T = 1, dlt = 0.9999, eps = 1e-9;
int run = 0;
for(double t = T; t > eps; t *= dlt) {
run++;
int p = vec[rnd(1, m)], q;
do q = New(); while(in[q]) ;
int tmp = mx;
Ins(q), Era(p);
if(Chkmin(mn, mx)) ans = vec;
if((mx > tmp) && (exp((tmp - mx) / t) < rd())) Ins(p), Era(q);
}
cerr << "run = " << run << ": " << mn << " " << mx << endl;
}
int main() {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
cin >> type >> n >> m >> V;
if(type == 2) {
for(int i = 1; i <= n; i++) can[i] = IsPrime(i);
} else if(type == 3) {
for(int i = 1; i <= n; i++) can[i] = 1;
} else if(type == 4) {
int c, x;
cin >> c;
while(c--) cin >> x, can[x] = 1;
for(int i = 1; i <= n; i++) cerr << can[i];
cerr << endl;
}
for(int i = 1; i <= V; i++) {
for(int j = 1; j <= V; j++) {
g[i][j] = __gcd(i, j);
}
}
for(int i = 1; i <= V; i++) {
if(D(i) >= 4) all.push_back(i);
}
set <int> st {0, V + 1};
while(st.size() - 2 < m) st.insert(New());
vec = vector<int> (st.begin(), st.end());
for(int i = 1; i <= m; i++) {
in[vec[i]] = 1;
}
for(auto it = st.begin(); it != prev(st.end()); it++) {
int l = *it, r = *next(it);
if(l && can[l]) Upd(l, 1);
for(int i = l + 1; i < r; i++) {
if(can[i]) Upd(g[l][i] + g[r][i] - g[l][r], 1);
}
}
cerr << "mx = " << mx << endl;
mn = mx, ans = vec;
for(int i = 0; i < 40; i++) SA();
cout << "mn = " << mn << "\n";
cout << "{";
for(int i = 1; i <= m; i++) {
cout << ans[i];
if(i != m) cout << ", ";
}
cout << "}\n";
map <int, int> mp;
st = set<int> (ans.begin(), ans.end());
for(auto it = st.begin(); it != prev(st.end()); it++) {
int l = *it, r = *next(it);
if(l && can[l]) mp[l]++;
cerr << l << " " << r << ": " << g[l][r] << endl;
for(int i = l + 1; i < r; i++) {
if(can[i]) mp[g[l][i] + g[r][i] - g[l][r]]++;
}
}
for(auto [v, c] : mp) cerr << v << " " << c << endl;
return 0;
}
浙公网安备 33010602011771号