LGP17665 IO 2025 #3 LOIS
原题链接:IO 2025 #3 LOIS
分析
昨天晚上在操场跑步的时候 l y x lyx lyx 给我说了这个题。然后跑了 200 200 200 米之后我就会了。就是一些分讨。你做完了......
傻子 special judge🤬
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 300005;
int n, k;
int a[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
int cnt0 = 0;
for (int i = 1; i <= n; i++){
cin >> a[i];
if (a[i] == 0)
cnt0++;
}
if (cnt0 != 0){
cout << n + 1 << '\n';
for (int i = 1; i <= n; i++)
cout << a[i] << ' ';
cout << 0 << '\n';
return 0;
}
int cnt2 = 0;
for (int i = 1; i <= n; i++){
if (a[i] == 2)
cnt2++;
}
if (cnt2 >= 2 && k >= 4){
cout << n - 1 << '\n';
int f = 0;
for (int i = 1; i <= n; i++){
if (a[i] == 2) {
f++;
if (f == 2)
cout << 4 << ' ';
if (f > 2)
cout << 2 << ' ';
}
else{
cout << a[i] << ' ';
}
}
cout << '\n';
return 0;
}
sort(a + 1, a + n + 1);
if (a[1] == a[n]){
bool ok = false;
for (int i = 2; i * i <= a[1]; i++){
if (a[1] % i == 0) {
int j = a[1] / i;
cout << n + 1 + a[1] - i - j << '\n';
cout << j << ' ' << i << ' ';
for (int t = 1; t <= a[1] - i - j; t++){
cout << 1 << ' ';
}
for (int t = 2; t <= n; t++){
cout << a[t] << ' ';
}
cout << '\n';
ok = true;
break;
}
}
if (!ok)
cout << -1 << '\n';
}
else{
cout << n << '\n';
swap(a[1], a[n]);
for (int i = 1; i <= n; i++){
cout << a[i] << ' ';
}
cout << '\n';
}
return 0;
}
LGP2862 USACO06JAN Corral the Cows G
原题链接:USACO06JAN Corral the Cows G
分析
思考一下,那我直接二分边长,然后 n 2 n^2 n2 check?这个好像有点超时......那不如枚举三叶草数量然后算最小的边长。
哦,这个是不是真的可以写......呃,好像需要什么线段树之类的东西?慢慢想,别急。
不是,这个,我把所有的三叶草都排到 x x x 轴上,然后,枚举起点,二分出来第一个大于 C C C 的位置,然后,找出 y y y 的最大值,是不是做完了?对吧......那,直接开写吧......有点怵......加油,试一下嘛......
其实直接二分就行了。
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 10005;
int c, n;
struct node{
int x, y;
}inp[N];
int sum[N][N];
vector<int> a;
bool check(int x){
for (int i = 0, j = 1; j < (int)a.size(); j++){
while (a[j] - a[i + 1] + 1 > x)
i++;
for (int k = 0, l = 1; l < (int)a.size(); l++){
while (a[l] - a[k + 1] + 1 > x)
k++;
if (sum[j][l] - sum[i][l] - sum[j][k] + sum[i][k] >= c){
return true;
}
}
}
return false;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> c >> n;
a.push_back(0);
for (int i = 1; i <= n; i++){
cin >> inp[i].x >> inp[i].y;
a.push_back(inp[i].x);
a.push_back(inp[i].y);
}
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
for (int i = 1; i <= n; i++){
int pos1 = lower_bound(a.begin(), a.end(), inp[i].x) - a.begin();
int pos2 = lower_bound(a.begin(), a.end(), inp[i].y) - a.begin();
sum[pos1][pos2]++;
}
for (int i = 1; i < N; i++){
for (int j = 1; j < N; j++){
sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
}
}
int l = 1, r = 10000;
while (l < r){
int mid = (l + r) >> 1;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << l;
}
LGP3201 HNOI2009 梦幻布丁
原题链接:HNOI2009 梦幻布丁
分析
如果真的是启发式合并的话......那不是特别难想吧......
呃,我拿 set 记录每个颜色的段,那么,对于合并,我们只需要判断是不是与合并的相互重合即可,然后,全局记录一个东西,做完了......怎么写代码呢?
我并不会写 merge 部分😭
找 A I AI AI 调一下......
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005, M = 1000005;
int n, m;
vector<int> pos[M];
int sz[M];
int rl[M];
int id[M];
int col[N];
int ans;
void merge(int cx, int cy, int tar){
for (int p : pos[cx]) {
if (p > 1 && rl[col[p - 1]] == tar)
ans--;
if (p < n && rl[col[p + 1]] == tar)
ans--;
}
for (int p : pos[cx]){
col[p] = cy;
pos[cy].push_back(p);
}
sz[cy] += sz[cx];
sz[cx] = 0;
pos[cx].clear();
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++){
cin >> col[i];
pos[col[i]].push_back(i);
sz[col[i]]++;
}
for (int i = 1; i < M; i++){
rl[i] = i;
id[i] = i;
}
for (int i = 1; i <= n; i++){
if (rl[col[i]] != rl[col[i - 1]])
ans++;
}
for (int cs = 1, op, x, y; cs <= m; cs++){
cin >> op;
if (op == 1){
cin >> x >> y;
if (x == y)
continue;
int cx = id[x], cy = id[y];
if (cx == cy)
continue;
if (sz[cx] > sz[cy]){
swap(rl[cx], rl[cy]);
swap(id[x], id[y]);
swap(cx, cy);
}
merge(cx, cy, rl[cy]);
}
if (op == 2){
cout << ans << '\n';
}
}
return 0;
}
CF600E Lomsat gelral
原题链接:E. Lomsat gelral
分析
这个写一个树上启发式合并,每个点开一个 set 维护颜色个数和颜色编号,在每棵子树的根出合并,然后做完了。
别卡常了😭
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n;
int col[N];
vector<int> e[N];
int sz[N], son[N];
int cnt[N];
int mx, sum;
int ans[N];
void dfs1(int u, int fa){
sz[u] = 1;
for (auto v : e[u]){
if (v == fa)
continue;
dfs1(v, u);
sz[u] += sz[v];
if (sz[v] > sz[son[u]])
son[u] = v;
}
}
void add(int c, int val){
if (val == 1){
cnt[c]++;
if (cnt[c] > mx){
mx = cnt[c];
sum = c;
}
else if (cnt[c] == mx){
sum += c;
}
}
else{
cnt[c]--;
}
}
void dfs_add(int u, int fa, int val){
add(col[u], val);
for (auto v : e[u]){
if (v == fa)
continue;
dfs_add(v, u, val);
}
}
void dfs2(int u, int fa, int keep){
for (auto v : e[u]){
if (v == fa || v == son[u])
continue;
dfs2(v, u, 0);
}
if (son[u]){
dfs2(son[u], u, 1);
}
for (auto v : e[u]){
if (v == fa || v == son[u])
continue;
dfs_add(v, u, 1);
}
add(col[u], 1);
ans[u] = sum;
if (keep == 0){
dfs_add(u, fa, -1);
mx = 0;
sum = 0;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++){
cin >> col[i];
}
for (int i = 1, u, v; i < n; i++){
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1, 0);
dfs2(1, 0, 1);
for (int i = 1; i <= n; i++){
cout << ans[i] << " ";
}
return 0;
}