LGP12561 UTS 2024 Matrix
原题链接:UTS 2024 Matrix
分析
居然是一个三维数点问题吗?天啊。
考虑 ( i 1 , j 1 ) (i_1,j_1) (i1,j1) 对 ( i 2 , j 2 ) (i_2,j_2) (i2,j2) 有贡献,当且仅当:
- i 1 ≤ i 2 i_1\le i_2 i1≤i2, j 1 ≥ j 2 j_1\ge j_2 j1≥j2, ∣ i 1 − i 2 ∣ + ∣ j 1 − j 2 ∣ < k |i_1-i_2|+|j_1-j_2|< k ∣i1−i2∣+∣j1−j2∣<k
简写为:
j 1 − i 1 ≤ j 2 − i 2 + k − 1 j_1-i_1\le j_2-i_2+k-1 j1−i1≤j2−i2+k−1
写个 CDQ 就没事了。
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2005;
pair<int, int> c[N << 1];
pair<int, int> operator + (const pair<int, int> &a, const pair<int, int> &b){
if (a.first < b.first){
return b;
}
if (a.first > b.first){
return a;
}
return {a.first, a.second + b.second};
}
void clear(){
for (int i = 0; i < (N << 1); i++){
c[i] = {-1, 0};
}
}
void add(int x, pair<int, int> val){
for (int i = x; i < (N << 1); i += i & (-i)){
c[i] = c[i] + val;
}
}
pair<int, int> query(int x){
x = min(x, (N << 1) - 1);
pair<int, int> res = {-1, 0};
for (int i = x; i; i -= i & (-i)){
res = res + c[i];
}
return res;
}
int n, m, k, a[N][N];
pair<int, int> ans[N][N];
void work(int l, int r){
if (l == r){
clear();
for (int i = 1; i <= n; i++){
add(l - i + n, {a[i][l], 1});
ans[i][l] = ans[i][l] + query(l - i + n + k - 1);
}
return ;
}
int mid = (l + r) >> 1;
work(l, mid);
work(mid + 1, r);
clear();
for (int i = 1; i <= n; i++){
for (int j = mid + 1; j <= r; j++){
add(j - i + n, {a[i][j], 1});
}
for (int j = l; j <= mid; j++){
ans[i][j] = ans[i][j] + query(j - i + n + k - 1);
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
cin >> a[i][j];
ans[i][j] = {-1, 0};
}
}
work(1, m);
for (int i = k; i <= n; i++){
for (int j = 1; j + k - 1 <= m; j++){
cout << ans[i][j].first << " ";
}
cout << '\n';
}
for (int i = k; i <= n; i++){
for (int j = 1; j + k - 1 <= m; j++){
cout << ans[i][j].second << " ";
}
cout << '\n';
}
}
AT_arc150_d ARC150D Removing Gacha
分析
别急,这咋做😭
哦,我读懂题了!!!
我们发现,出现问题在于有些点的祖先没有被染。
那么,我们尝试设一下 DP 式子......
难道我设 d p c n t dp_{cnt} dpcnt 表示有 c n t cnt cnt 个点是染成黑色但是仍然是"坏节点"?那这个咋转移啊?这个估计没法转移。
那么,我们假设操作次数?设 d p i dp_{i} dpi 表示进行 i i i 次操作的期望。那么,答案估计就是一个:
∑ i = n 2 n − 1 d p i \sum\limits_{i=n}^{2n-1}dp_{i} i=n∑2n−1dpi
的状物?
那么,我们需要明确的就是每一次的操作序列。这个本质还是一个计数,我们继续思考......
对于进行恰好 n n n 次操作,这个说的好怪,我们发现只会出现 n n n 次操作,我们需要知道的不过是概率。
那也不对啊......
这么困难吗😭
bur,咋一个
a n s = ∑ i = 1 n ∑ j = 1 d e i 1 j ans=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{de_i}\dfrac{1}{j} ans=i=1∑nj=1∑deij1
就解决了😭
问题的本质是: d i d_i di 个点,每次等概率抽取一个点,抽到第 d i d_i di 个点时贡献加 1 1 1,一直抽直到所有点都被抽到过。
不是哥们😭
正解
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 200005;
int n;
int sum[N], de[N];
vector<int> e[N];
int qpow(int a, int b){
int res = 1;
while (b){
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void dfs(int u, int fa){
de[u] = de[fa] + 1;
sum[u] = (sum[fa] + qpow(de[u], mod - 2)) % mod;
for (auto v : e[u]){
if (v == fa)
continue;
dfs(v, u);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 2, p; i <= n; i++){
cin >> p;
e[p].push_back(i);
e[i].push_back(p);
}
de[1] = 1;
dfs(1, 0);
int ans = 0;
for (int i = 1; i <= n; i++){
ans = (ans + sum[i]) % mod;
}
cout << ans;
}
LGP17320 ICPC 2018 Nanjing R Cherry and Chocolate
原题链接:ICPC 2018 Nanjing R Cherry and Chocolate
分析
我们发现,在第一次放完粉色之后,我们会放棕色,然后再放粉色,使得棕色是最大子树的重心,然后第二个粉色又是最大子树的重心,然后做完了。
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, fa[N], sz[N];
vector<pair<int, int>> e[N];
pair<int, int> id[N << 1];
int nxt[N << 1][20];
int mx[N], siz[N << 1];
int mmx[N];
int cnt[N << 1];
void dfs(int u){
sz[u] = 1;
for (auto tmp : e[u]) {
if (tmp.first == fa[u])
continue;
fa[tmp.first] = u;
dfs(tmp.first);
sz[u] += sz[tmp.first];
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1, u, v; i < n; i++){
cin >> u >> v;
e[u].push_back({v, (i - 1) * 2});
e[v].push_back({u, (i - 1) * 2 + 1});
id[(i - 1) * 2] = {u, v};
id[(i - 1) * 2 + 1] = {v, u};
}
dfs(1);
int m = (n - 1) << 1;
for (int i = 0; i < m; i++){
auto tmp = id[i];
if (fa[tmp.second] == tmp.first){
siz[i] = sz[tmp.second];
}
else{
siz[i] = n - sz[tmp.first];
}
}
for (int u = 1; u <= n; u++){
mx[u] = mmx[u] = -1;
for (auto tmp : e[u]){
if (mx[u] == -1 || siz[tmp.second] > siz[mx[u]]){
mmx[u] = mx[u];
mx[u] = tmp.second;
}
else if (mmx[u] == -1 || siz[tmp.second] > siz[mmx[u]]){
mmx[u] = tmp.second;
}
}
}
memset(nxt, -1, sizeof(nxt));
for (int i = 0; i < m; i++) {
int u = id[i].second;
if (mx[u] != (i ^ 1))
nxt[i][0] = mx[u];
else
nxt[i][0] = mmx[u];
}
for (int i = 1; i < 20; i++){
for (int j = 0; j < m; j++){
if (nxt[j][i - 1] == -1)
nxt[j][i] = -1;
else
nxt[j][i] = nxt[nxt[j][i - 1]][i - 1];
}
}
for (int i = 0; i < m; i++){
int u = i;
for (int k = 19; k >= 0; k--){
int ne = nxt[u][k];
if (ne != -1 && siz[ne] * 2 > siz[i])
u = ne;
}
if (nxt[u][0] != -1)
cnt[i] = siz[i] - max(siz[i] - siz[u], siz[nxt[u][0]]);
else
cnt[i] = siz[i] - max(siz[i] - siz[u], 0);
}
int ans = n;
for (int u = 1; u <= n; u++){
int val = 0;
for (auto tmp : e[u]){
val = max(val, cnt[tmp.second]);
}
ans = min(ans, val);
}
cout << n - ans;
return 0;
}