E
调和级数
对一个数列,问每个aia_iai,选kkk个数,包含aia_iai,最大的gcdgcdgcd是多少
注意到gcdgcdgcd有一个性质,他一定是所有数的因子,并且还是最大的那个。所以这种至少是kkk个数的最大gcdgcdgcd的问题,一种做法是,枚举答案,然后枚举倍数,检查他的倍数是否至少有kkk个。如果是,那么这个枚举的数,就一定是至少kkk个数的因数,并且可能是这些数的gcdgcdgcd。要求gcdgcdgcd的话,仍然可以这样枚举下去,因为最大的gcdgcdgcd一定会被我们枚举到。
然后这里进阶一点的问题是,多次询问,每次问包含aia_iai的kkk个数的最大gcdgcdgcd。仍然可以上述的调和级数枚举,然后对于一个答案xxx,如果他是合法的,即倍数超过kkk个,那么他的所有倍数的答案都可以是xxx,用xxx更新所有倍数的答案,更新是取maxmaxmax。
这里我们就记录了所有值的答案,输出答案时根据aia_iai的值查表即可
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, k;
cin >> n >> k;
vector<int>a(n);
int mx = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
mx = max(mx, a[i]);
}
vector<int>b(mx + 1);
for (int x : a) {
b[x]++;
}
vector<int>ans(mx + 1);
for (int i = 1; i <= mx; i++) {
int cnt = 0;
for (int j = i; j <= mx; j += i) {
cnt += b[j];
}
if (cnt >= k) {
for (int j = i; j <= mx; j += i) {
ans[j] = i;
}
}
}
for (int x : a) {
cout << ans[x] << '\n';
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin>>T;
while (T--) {
solve();
}
return 0;
}
F
线段树 LIS 离线
多次询问,每次问只用前缀[1,ri][1,r_i][1,ri]里的元素,能得到的,最大值不超过xix_ixi的严格LISLISLIS的长度。
注意到LISLISLIS里最大元素就是结尾元素,所以问的就是结尾元素不超过xix_ixi的LISLISLIS。然后每次询问不一定是对整个序列的dpdpdp结果来说的,可能是对某个前缀的dpdpdp结果来说的。那么就把询问离线,在dpdpdp到一个前缀[1,i][1,i][1,i]时,回答r=ir=ir=i的所有询问。
实现上就是一个线段树优化LISLISLIS,回答询问也是一个类似LISLISLIS的转移,查询结尾元素在[1,xi][1,x_i][1,xi]内的最长LISLISLIS线段树查询即可。
ai,xia_i,x_iai,xi很大,我们要用线段树维护值域,则需要先离散化。
#include <bits/stdc++.h>
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N = 4e5 + 10;
struct tree {
struct node {
int l, r, mx;
} tr[N << 2];
void pushup(int u) {
tr[u].mx = max(tr[ls].mx, tr[rs].mx);
}
void build(int u, int l, int r) {
tr[u] = {l, r, 0};
if (l == r) {
return;
}
int m = l + r >> 1;
build(ls, l, m);
build(rs, m + 1, r);
}
void upd(int u, int idx, int v) {
if (tr[u].l == tr[u].r) {
tr[u].mx = max(tr[u].mx, v);
return;
}
int m = (tr[u].l + tr[u].r) / 2;
if (idx <= m) {
upd(ls, idx, v);
} else {
upd(rs, idx, v);
}
pushup(u);
}
int ask(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) {
return tr[u].mx;
}
int m = (tr[u].l + tr[u].r) / 2;
if (l > m) {
return ask(rs, l, r);
} else if (r <= m) {
return ask(ls, l, r);
}
return max(ask(ls, l, r), ask(rs, l, r));
}
} t;
void solve() {
int n, q;
cin >> n >> q;
vector<int>all;
vector<int>a(n);
for (int &x : a) {
cin >> x;
all.push_back(x);
}
vector<int>r(q), x(q);
for (int i = 0; i < q; i++) {
cin >> r[i] >> x[i];
all.push_back(x[i]);
}
sort(all.begin(), all.end());
all.erase(unique(all.begin(), all.end()), all.end());
for (int i = 0; i < n; i++) {
a[i] = lower_bound(all.begin(), all.end(), a[i]) - all.begin() + 1;
}
for (int i = 0; i < q; i++) {
x[i] = lower_bound(all.begin(), all.end(), x[i]) - all.begin() + 1;
}
vector<vector<pair<int, int>>>Q(n);
for (int i = 0; i < q; i++) {
Q[r[i] - 1].emplace_back(x[i], i);
}
vector<int>ans(q);
t.build(1, 0, all.size());
for (int i = 0; i < n; i++) {
int mx = t.ask(1, 0, a[i] - 1);
// cout << a[i] << ':';
t.upd(1, a[i], mx + 1);
// cout << mx + 1 << '\n';
for (auto [x, id] : Q[i]) {
ans[id] = t.ask(1, 0, x);
}
}
for (int x : ans) {
cout << x << '\n';
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin>>T;
while (T--) {
solve();
}
return 0;
}
699

被折叠的 条评论
为什么被折叠?



