P17142 [NOI 2026] 布丁
Genius_Star · · 题解
来一个打表做法,vp 的时候爬山写挂了,一直在调整固定一个位置的值,跑出来的仅仅获得了 29pts。
思路:
首先注意到若我们选择了一个包含
那么有一个很暴力的做法,询问一下
考虑优化,对于第一次询问,我们可以将
因为
这样爬山对
::::info[第一次询问打表]
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
const int N = 3030, M = 1e5;
int n;
int a[N], cnt[M];
inline int get(vector<int> &a){
int s = 0;
for (int i = 1; i < (int)a.size(); ++i)
s += __gcd(a[i - 1], a[i]);
return s;
}
inline int getins(vector<int> &a, int lst, int w){
int n = a.size();
int p = lower_bound(a.begin(), a.end(), w) - a.begin();
if(p < n && a[p] == w)
return lst + w;
if(!p)
return lst + __gcd(w, a[0]);
if(p == n)
return lst + __gcd(w, a[n - 1]);
return lst - __gcd(a[p - 1], a[p]) + __gcd(w, a[p - 1]) + __gcd(w, a[p]);
}
inline int get(vector<int> &ask, vector<int> &a){
int mx = 0, lst = get(ask);
vector<int> V;
for(auto i : a){
int w = getins(ask, lst, i);
if(!cnt[w])
V.push_back(w);
++cnt[w];
mx = max(mx, cnt[w]);
}
for(auto v : V)
cnt[v] = 0;
return mx;
}
mt19937 R(time(0));
inline void init(){
for(int i = 1; i <= n; ++i)
cin >> a[i];
}
int main(){
cin >> n;
// init();
int T;
int mn = 1e9;
cin >> T;
vector<int> now;
for(int i = 1; i <= 3000; ++i)
now.push_back(i);
a[0] = 1, a[n + 1] = 4500;
while(mn > 100){
vector<int> ask;
for(int i = 1; i <= n; ++i){
a[i] = R() % 3000 + 1;
ask.push_back(a[i]);
}
sort(ask.begin(), ask.end());
sort(a + 1, a + n + 1);
int w = get(ask, now);
int TT = 1000;
while(TT--){
int x = R() % n + 1;
int lst = a[x];
a[x] = a[x - 1] + R() % (a[x + 1] - a[x - 1] + 1);
ask[x - 1] = a[x];
int ww = get(ask, now);
if(ww > w){
a[x] = lst;
ask[x - 1] = a[x];
}
else
w = ww;
}
if(w < mn){
mn = w;
for(auto v : ask){
cout << v << ' ';
}
cout << '\n';
cerr << w << '\n';
}
}
return 0;
}
/*
180 483 924 1344 1890 2415 2968
124
*/
::::
通过这次询问,对于划分的若干等价类,显然大小
于是,对第一次询问划分下来的每个等价类再次打表出询问,使用上面的爬山随机法,直到
如果你 rp 不是很好,第二次询问也没有跑出来,别慌,还有第三次,对第二次询问划分的等价类再跑随机,显然表是够的。
::::info[第二次询问打表]
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
const int N = 3030, M = 1e5;
int n;
int a[N], cnt[M];
vector<int> P[M];
mt19937 R(time(0));
inline int get(vector<int> &a){
int s = 0;
for (int i = 1; i < (int)a.size(); ++i)
s += __gcd(a[i - 1], a[i]);
return s;
}
inline int getins(vector<int> &a, int lst, int w){
int n = a.size();
int p = lower_bound(a.begin(), a.end(), w) - a.begin();
if(p < n && a[p] == w)
return lst + w;
if(!p)
return lst + __gcd(w, a[0]);
if(p == n)
return lst + __gcd(w, a[n - 1]);
return lst - __gcd(a[p - 1], a[p]) + __gcd(w, a[p - 1]) + __gcd(w, a[p]);
}
inline int get(vector<int> &ask, vector<int> &a){
int mx = 0, lst = get(ask);
vector<int> V;
for(auto i : a){
int w = getins(ask, lst, i);
if(!cnt[w])
V.push_back(w);
++cnt[w];
mx = max(mx, cnt[w]);
}
for(auto v : V)
cnt[v] = 0;
return mx;
}
inline vector<int> create(int n, vector<int> &now, int lim){
a[0] = 1, a[n + 1] = 4500;
int mn = 1e9;
vector<int> rask;
while(mn > lim){
vector<int> ask;
for(int i = 1; i <= n; ++i){
a[i] = R() % 3000 + 1;
ask.push_back(a[i]);
}
sort(ask.begin(), ask.end());
sort(a + 1, a + n + 1);
int w = get(ask, now);
int TT = 100;
while(TT--){
int x = R() % n + 1;
int lst = a[x];
a[x] = a[x - 1] + R() % (a[x + 1] - a[x - 1] + 1);
ask[x - 1] = a[x];
int ww = get(ask, now);
if(ww > w){
a[x] = lst;
ask[x - 1] = a[x];
}
else
w = ww;
}
if(w < mn){
mn = w;
rask = ask;
// for(auto v : ask){
// cout << v << ' ';
// }
// cout << '\n';
// cerr << w << '\n';
}
}
return rask;
}
inline void getsave(vector<int> &ask, vector<int> &a){
int lst = get(ask);
vector<int> V;
for(auto i : a){
int w = getins(ask, lst, i);
if(!cnt[w])
V.push_back(w);
++cnt[w];
P[w].push_back(i);
}
for(auto v : V){
cnt[v] = 0;
if((int)P[v].size() <= 28)
continue;
// cout << P[v].size() << ':';
// for(auto i : P[v])
// cout << i << ' ';
// cout << '\n';
auto getask = create(6, P[v], 22);
cout << "Q[" << v << ']' << " = {";
for(int i = 0; i < (int)getask.size(); ++i)
cout << getask[i] << (i == (int)getask.size() - 1 ? "};" : ", ");
cout << '\n';
}
return ;
}
inline void init(){
for(int i = 1; i <= n; ++i)
cin >> a[i];
vector<int> ask;
for(int i = 1; i <= n; ++i)
ask.push_back(a[i]);
sort(ask.begin(), ask.end());
vector<int> now;
for(int i = 1; i <= 3000; ++i)
now.push_back(i);
getsave(ask, now);
}
int main(){
cin >> n;
init();
// int T;
// int mn = 1e9;
// cin >> T;
// vector<int> now;
// for(int i = 1; i <= 3000; ++i)
// now.push_back(i);
return 0;
}
/*
7
180 483 924 1344 1890 2415 2968
124
*/
::::
代码实现的时候把表在 init 时预处理好,询问的时候直接问即可。
完整代码:
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
#include "pudding.h"
const int N = 3030, M = 1e5;
int n;
int a[N], cnt[M], id[N], ccnt[M];
vector<int> P[M], Q[M], PP[M];
mt19937 R(time(0));
inline int get(vector<int> &a){
int s = 0;
for (int i = 1; i < (int)a.size(); ++i)
s += __gcd(a[i - 1], a[i]);
return s;
}
inline int getins(vector<int> &a, int lst, int w){
int n = a.size();
int p = lower_bound(a.begin(), a.end(), w) - a.begin();
if(p < n && a[p] == w)
return lst + w;
if(!p)
return lst + __gcd(w, a[0]);
if(p == n)
return lst + __gcd(w, a[n - 1]);
return lst - __gcd(a[p - 1], a[p]) + __gcd(w, a[p - 1]) + __gcd(w, a[p]);
}
inline int get(vector<int> &ask, vector<int> &a){
int mx = 0, lst = get(ask);
vector<int> V;
for(auto i : a){
int w = getins(ask, lst, i);
if(!cnt[w])
V.push_back(w);
++cnt[w];
mx = max(mx, cnt[w]);
}
for(auto v : V)
cnt[v] = 0;
return mx;
}
inline void getsave(vector<int> &ask, vector<int> &a){
int lst = get(ask);
vector<int> V;
for(auto i : a){
int w = getins(ask, lst, i);
if(!cnt[w])
V.push_back(w);
++cnt[w];
P[w].push_back(i);
}
for(auto v : V)
cnt[v] = 0;
return ;
}
void init(int c, int t){
vector<int> now;
for(int i = 1; i <= 3000; ++i)
now.push_back(i);
vector<int> base = {180, 483, 924, 1344, 1890, 2415, 2968};
getsave(base, now);
Q[263] = {98, 160, 900, 1435, 2764, 3344};
Q[264] = {92, 343, 1229, 1352, 2727, 3549};
Q[265] = {149, 360, 530, 2395, 3344, 3572};
Q[266] = {160, 2370, 3296, 3501, 3855, 4472};
Q[268] = {255, 476, 1348, 1712, 2189, 4445};
Q[271] = {264, 446, 895, 1170, 3043, 3139};
Q[261] = {55, 285, 369, 1782, 2125, 3428};
Q[262] = {324, 561, 1687, 1853, 2152, 4350};
Q[243] = {60, 572, 650, 753, 855, 3132};
Q[250] = {632, 654, 1143, 2343, 3921, 4384};
Q[246] = {655, 1080, 3151, 3574, 3640, 4005};
Q[247] = {256, 326, 626, 684, 2989, 3052};
Q[256] = {387, 632, 737, 2544, 2978, 3923};
Q[244] = {675, 795, 1926, 2170, 2672, 3335};
Q[180] = {70, 1025, 1118, 1230, 1581, 2982};
Q[182] = {672, 1064, 1133, 1298, 3847, 4100};
Q[184] = {166, 733, 927, 1073, 1255, 2985};
Q[190] = {975, 1107, 1336, 2449, 3074, 3295};
Q[202] = {616, 1152, 3589, 3635, 3907, 3981};
Q[234] = {340, 1605, 2148, 2188, 2688, 4377};
Q[226] = {67, 608, 1011, 1492, 1716, 3757};
Q[238] = {696, 1659, 2650, 3317, 3695, 3898};
Q[224] = {361, 1331, 1356, 1551, 1757, 3408};
Q[222] = {1218, 1463, 1587, 1692, 1798, 4433};
Q[232] = {592, 1474, 1570, 1941, 2008, 4344};
Q[159] = {1872, 1988, 2046, 2142, 2232, 2328};
Q[160] = {240, 327, 528, 2100, 2255, 3772};
Q[163] = {5, 363, 429, 2138, 2261, 2436};
Q[166] = {235, 1078, 2268, 2960, 3934, 4120};
Q[172] = {935, 1078, 1125, 2055, 2161, 3356};
Q[178] = {205, 637, 787, 952, 2299, 2505};
Q[257] = {2292, 2502, 2618, 2717, 2856, 4472};
Q[260] = {143, 702, 2548, 2584, 2819, 4359};
Q[259] = {232, 821, 922, 1124, 1278, 2718};
Q[258] = {519, 790, 888, 1411, 2584, 2795};
}
int find_tastiness(int c, int m){
if(m <= 35){
vector<int> ask;
for(int i = 1; i <= m; ++i)
ask.push_back(i);
return query_tastiness(ask) - get(ask);
}
vector<int> ask = {180, 483, 924, 1344, 1890, 2415, 2968};
int w = query_tastiness(ask);
if(Q[w].empty()){
assert((int)P[w].size() <= 28);
ask.clear();
for(auto i : P[w])
ask.push_back(i);
return query_tastiness(ask) - get(ask);
}
ask = Q[w];
int lst = get(ask);
vector<int> V;
for(auto i : P[w]){
int t = getins(ask, lst, i);
if(!ccnt[t])
V.push_back(t);
++ccnt[t];
PP[t].push_back(i);
}
w = query_tastiness(ask);
ask = PP[w];
for(auto v : V)
PP[v].clear(), ccnt[v] = 0;
return query_tastiness(ask) - get(ask);
}