「JOI 2018 Final」簡要題解
阿新 • • 發佈:2018-12-22
題目是LOJ2347-LOJ2351
「JOI 2018 Final」寒冬暖爐
貪心小水題。選最大的間隔即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int n, k, T[maxn], ans, a[maxn];
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
int main()
{
n = gi(); k = gi(); --k;
for (int i = 1; i <= n; ++i) T[i] = gi();
for (int i = 2; i <= n; ++i) a[i] = T[i] - (T[i - 1] + 1);
ans = T[n] - T[1] + 1;
sort(a + 1, a + n + 1, greater<int>());
for (int i = 1; i <= k; ++i) ans -= a[i];
printf("%d\n", ans);
return 0;
}
「JOI 2018 Final」美術展覽
貪心小水題。用字首和轉化式子然後選最大最小即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
const int maxn = 500005;
int n;
lint Max[maxn], sum[maxn], ans;
struct node
{
lint A, B;
bool operator < (const node &x) {
return A < x.A;
}
} p[maxn];
inline lint gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
lint sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
int main()
{
n = gi();
for (int i = 1; i <= n; ++i) p[i].A = gi(), p[i].B = gi();
sort(p + 1, p + n + 1);
Max[0] = -(1ll << 60);
for (int i = 1; i <= n; ++i) {
sum[i] = sum[i - 1] + p[i].B;
Max[i] = max(Max[i - 1], p[i].A - sum[i - 1]);
}
lint Min = 1ll << 60;
for (int i = n; i >= 1; --i) {
if (Min > p[i].A - sum[i]) Min = p[i].A - sum[i];
ans = max(ans, Max[i] - Min);
}
printf("%lld\n", ans);
return 0;
}
「JOI 2018 Final」糰子製作
非常有意思的一道DP。考慮不在同一對角線的糰子串不會互相影響,所以在對角線上進行DP。狀態為橫放/豎放/不放。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3005;
int n, m;
char s[maxn][maxn];
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline int check(int x, int y)
{
return (s[x - 1][y] == 'R' && s[x][y] == 'G' && s[x + 1][y] == 'W') << 1 |
(s[x][y - 1] == 'R' && s[x][y] == 'G' && s[x][y + 1] == 'W');
}
int main()
{
n = gi(); m = gi();
for (int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
register int x, y, t, A, B, C, g, ans = 0;
for (int i = 1; i <= n + m - 1; ++i) {
x = min(i, n), y = max(1, i - n + 1), A = 0, B = 0, C = 0;
while (x && y <= m) {
t = check(x, y), g = C;
C = max(C, max(A, B));
if (t & 1) A = max(A, g) + 1;
if (t & 2) B = max(B, g) + 1;
--x; ++y;
}
ans += max(A, max(B, C));
}
printf("%d\n", ans);
return 0;
}
「JOI 2018 Final」月票購買
考慮一定存在一種方案,使得 的最短路的交集一定是連續的。
所以隱式建出 的最短路DAG,選出一條 的最短路上的兩個點 ,使得 最小。
答案就是上式與 取 。
#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
const int maxn = 100005;
int n, m, s, t, u, v;
struct edge
{
int to, next, w;
} e[maxn * 4];
int h[maxn], tot;
lint dis_s[maxn], dis_t[maxn], dis_u[maxn], dis_v[maxn];
bool vis[maxn];
priority_queue<pair<lint, int>, vector<pair<lint, int> >, greater<pair<lint, int> > > que;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline void add(int u, int v, int w)
{
e[++tot] = (edge) {v, h[u], w}; h[u] = tot;
e[++tot] = (edge) {u, h[v], w}; h[v] = tot;
}
void dijkstra(int s, lint *dis)
{
memset(dis + 1, 63, sizeof(lint) * n);
memset(vis + 1, 0, sizeof(bool) * n);
dis[s] = 0;
que.push(make_pair(dis[s], s));
int u;
while (!que.empty()) {
u = que.top().second; que.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
que.push(make_pair(dis[v], v));
}
}
}
lint Min_u[maxn], Min_v[maxn], ans = 1ll << 60;
void dfs(int x)
{
if (vis[x] == 1) return ;
vis[x] = 1;
Min_u[x] = dis_u[x];
Min_v[x] = dis_v[x];
for (int i = h[x], y; y = e[i].to, i; i = e[i].next)
if (dis_s[x] + dis_t[y] + e[i].w == dis_s[t]) {
dfs(y);
if (Min_u[x] + Min_v[x] > min(dis_u[x], Min_u[y]) + min(dis_v[x], Min_v[y])) {
Min_u[x] = min(dis_u[x], Min_u[y]);
Min_v[x] = min(dis_v[x], Min_v[y]);
}
}
ans = min(ans, dis_v[x]);
}
int main()
{
n = gi(); m = gi();
s = gi(); t = gi(); u = gi(); v = gi();
for (int u, v, i = 1; i <= m; ++i) u = gi(), v = gi(), add(u, v, gi());
dijkstra(s, dis_s);
dijkstra(t, dis_t);
dijkstra(u, dis_u);
dijkstra(v, dis_v);
memset(vis + 1, 0, sizeof(bool) * n);
dfs(s);
printf("%lld\n", min(Min_u[s] + Min_v[s], dis_u[v]));
return 0;
}
「JOI 2018 Final」毒蛇越獄
比較巧妙的題目。
可以發現,詢問串中的'0','1','?'
出現次數最少的字元的出現次數不會超過
。
那麼如果'0'
或'1'
出現次數最少,那麼可以用高維字首和進行容斥。否則,直接列舉'?'
代表的數統計答案即可。
時間複雜度: