A

统计后缀和

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef long long ll;
cs int N = 3e3 + 50;
int n, m; char mp[N][N];
int a[N][N], b[N][N];
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n >> m;
for(int i = 0; i < n; i++)
scanf("%s", mp[i]);
for(int i = 0; i < n; i++)
for(int j = m - 1; ~j; j--)
a[i][j] = a[i][j + 1] + (mp[i][j] == 'O');
for(int i = n - 1; ~i; i--)
for(int j = 0; j < m; j++)
b[i][j] = b[i + 1][j] + (mp[i][j] == 'I');
ll ans = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(mp[i][j] == 'J')
ans += a[i][j] * b[i][j];
cout << ans; return 0;
}

B

贪心,先按 JOI 2019 Final_#ifdef 排序,假设选了 JOI 2019 Final_#ifdef_02 个,那么一定会用最大的 JOI 2019 Final_#ifdef_02JOI 2019 Final_#ifdef_04
从后向前 JOI 2019 Final_#ifdef_05,求出到 JOI 2019 Final_i++_06 最多选几个即可,复杂度 JOI 2019 Final_#ifdef_07

#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define fi first
#define se second
using namespace std;
cs int N = 1e5 + 50;
typedef pair<int, int> pi;
int n, m;
pi a[N]; int c[N];
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n >> m;
for(int i = 1; i <= n; i++)
scanf("%d%d", &a[i].se, &a[i].fi);
sort(a + 1, a + n + 1);
for(int i = 1; i <= m; i++)
scanf("%d", &c[i]);
sort(c + 1, c + m + 1);
int mx = 0;
for(int i = n; i; i--){
int r = lower_bound(c + 1, c + m + 1, a[i].se) - c;
int z = min(mx + 1, m - r + 1);
mx = max(mx, z);
} cout << mx; return 0;
}

C

注意到相同颜色之间的顺序不会变
设计 JOI 2019 Final_#ifdef_08 表示已经放了 JOI 2019 Final_#define_09 个的逆序对数
复杂度 JOI 2019 Final_#ifdef_10

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 405;
int n, p, q, r;
char S[N]; int dp[N][N][N][3], sm[3][N], a[3][N];
void chkmn(int &a, int b){ if(a > b) a = b; }
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
scanf("%d%s", &n, S + 1);
for(int i = 1; i <= n; i++){
for(int j = 0; j < 3; j++)
sm[j][i] = sm[j][i - 1];
if(S[i] == 'R') a[0][++p] = i, ++sm[0][i];
if(S[i] == 'G') a[1][++q] = i, ++sm[1][i];
if(S[i] == 'Y') a[2][++r] = i, ++sm[2][i];
}
memset(dp, 0x3f, sizeof(dp));
dp[0][0][0][0] =
dp[0][0][0][1] =
dp[0][0][0][2] = 0;
static int v[3], w[3];
for(int i = 0; i <= p; i++)
for(int j = 0; j <= q; j++)
for(int k = 0; k <= r; k++){
v[0] = i, v[1] = j, v[2] = k;
for(int x = 0; x < 3; x++) if(v[x]){
for(int z = 0; z < 3; z++)
w[z] = v[z] - (x == z);
int c = 0, vl = 1e9;
for(int z = 0; z < 3; z++) if(z != x){
c += max(0, v[z] - sm[z][a[x][v[x]]]);
vl = min(vl, dp[w[0]][w[1]][w[2]][z]);
} if(vl < 1e9) dp[i][j][k][x] = vl + c;
}
}
int ans = 1e9;
for(int i = 0; i < 3; i++)
chkmn(ans, dp[p][q][r][i]);
ans = (ans == 1e9) ? -1 : ans;
cout << ans << '\n';
return 0;
}

D

将每个点移到最近的点
统计出 JOI 2019 Final_#define_11 表示还缺的个数
那么我们可以贪心从左边扫到右边,复杂度 JOI 2019 Final_#ifdef_12

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef long long ll;
cs int N = 1e5 + 50;
int n, c[N][2]; ll ans;
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n;
for(int i = 1, x, y; i <= n + n; i++){
scanf("%d%d", &x, &y); int _x, _y;
if(y <= 1) ans += 1 - y, _y = 0;
else ans += y - 2, _y = 1;
if(x < 1) _x = 1, ans += 1 - x;
else if(x > n) _x = n, ans += x - n;
else _x = x; ++c[_x][_y];
}
for(int i = 1; i <= n; i++)
for(int j = 0; j < 2; j++)
c[i][j] = 1 - c[i][j];
for(int i = 1; i <= n; i++){
if(c[i][0] > 0 && c[i][1] < 0){
int d = min(c[i][0], -c[i][1]);
c[i][0] -= d, c[i][1] += d, ans += d;
}
if(c[i][0] < 0 && c[i][1] > 0){
int d = min(-c[i][0], c[i][1]);
c[i][0] += d, c[i][1] -= d, ans += d;
}
ans += abs(c[i][0]) + abs(c[i][1]);
c[i + 1][0] += c[i][0];
c[i + 1][1] += c[i][1];
} cout << ans; return 0;
}

E

产生贡献的只能是 JOI 2019 Final_#ifdef_13 到直径的较远的一个端点的某一段
这启示我们从两个直径开始 JOI 2019 Final_i++_14,统计每个点的贡献
用栈维护根到当前点产生贡献的点以及个数
向下走一步要将其余儿子中最深的覆盖的那些点 JOI 2019 Final_i++_15
那么我们只需要先 JOI 2019 Final_i++_14 重儿子,复杂度 JOI 2019 Final_#ifdef_12

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 2e5 + 50;
int n, m, c[N];
vector<int> G[N];
int S, T, rt, mx;
void dfs(int u, int f, int d){
if(d > mx) mx = d, rt = u;
for(int v : G[u]) if(v != f)
dfs(v, u, d + 1);
}
int dep[N], mxd[N], son[N], se[N], ans[N];
void pre_dfs(int u, int f){
dep[u] = dep[f] + 1;
mxd[u] = se[u] = son[u] = 0;
for(int v : G[u]) if(v != f){
pre_dfs(v, u);
mxd[u] = max(mxd[u], mxd[v] + 1);
if(mxd[son[u]] <= mxd[v]) son[u] = v;
}
for(int v : G[u]) if(v != f && v != son[u])
se[u] = max(se[u], mxd[v] + 1);
}
int s[N], tp, bin[N], Sm;
void ins(int x){ Sm += !bin[x], ++bin[x]; }
void del(int x){ --bin[x], Sm -= !bin[x]; }
void sub_dfs(int u, int f){
while(tp && dep[u] - dep[s[tp]] <= se[u])
del(c[s[tp--]]);
ins(c[s[++tp] = u]);
if(son[u]) sub_dfs(son[u], u);
while(tp && dep[u] - dep[s[tp]] <= mxd[u])
del(c[s[tp--]]);
ans[u] = max(ans[u], Sm);
for(int v : G[u]) if(v != f && v != son[u]){
if(!tp || s[tp] != u)
ins(c[s[++tp] = u]); sub_dfs(v, u);
} if(tp && s[tp] == u)
del(c[s[tp--]]);
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n >> m;
for(int i = 1, u, v; i < n; i++)
scanf("%d%d", &u, &v),
G[u].pb(v), G[v].pb(u);
for(int i = 1; i <= n; i++)
scanf("%d", &c[i]);
dfs(1, 0, 0), S = rt; rt = mx = 0;
dfs(S, 0, 0), T = rt;
tp = 0, pre_dfs(S, 0), sub_dfs(S, 0);
tp = 0, pre_dfs(T, 0), sub_dfs(T, 0);
for(int i = 1; i <= n; i++)
cout << ans[i] << '\n';
return 0;
}