「比赛题解」AtCoder Beginner Contest 204 A-E简要题解
A:判断一下给出的俩是一样的还是不一样的,分成两类输出。
B:对于每个 \(A_i\),答案加上 \(\max(A_i-10,0)\)
C:对于每个点 \(\mathcal{O}(n)\) dfs 一遍能到达的点有多少个,加起来即可。
D:dp,设 \(f_{i,j}\) 为考虑前 \(i\) 个,是否存在“分成的两组较大的大小为 \(j\) ”的方案,dp复杂度 \(\mathcal{O}(n^2T)\)
E:Dij,每次算距离的时候三分一下,三分的时候按照不下取整算实数来三分,因为如果下取整的话会出现平的一段导致不能三分。
详细题解和代码有空补。
A
#include<iostream>
#include<cstdio>
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
signed main() {
int a, b;
read(a); read(b);
if(a == b) printf("%d\n", a);
else printf("%d\n", 3 - a - b);
return 0;
}
B
#include<iostream>
#include<cstdio>
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 1010;
int n, a[N], sum;
signed main() {
read(n);
for(int i = 1; i <= n; ++i) read(a[i]), sum += Max(0, a[i] - 10);
printf("%d\n", sum);
return 0;
}
C
#include<iostream>
#include<cstdio>
typedef long long ll;
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 2010;
int n, m, ent, head[N];
struct Edge {
int next, to;
}e[N << 1];
inline void add(int x, int y) {
e[++ent].to = y; e[ent].next = head[x]; head[x] = ent;
}
ll cnt, ans;
bool vis[N];
void dfs(int x) {
if(vis[x]) return ;
vis[x] = 1; ++cnt;
for(int i = head[x]; i; i = e[i].next) dfs(e[i].to);
}
signed main() {
read(n); read(m);
for(int i = 1, u, v; i <= m; ++i) {
read(u); read(v);
add(u, v); //add(v, u);
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) vis[j] = 0;
cnt = 0;
dfs(i);
ans += cnt;
}
printf("%lld\n", ans);
return 0;
}
D
#include<iostream>
#include<cstdio>
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 110;
int n, a[N], s[N];
bool f[N][N*1000];
signed main() {
read(n);
for(int i = 1; i <= n; ++i) read(a[i]), s[i] = s[i-1] + a[i];
f[1][a[1]] = 1;
for(int i = 1; i < n; ++i) {
for(int j = 0; j <= s[i]; ++j)
if(f[i][j])
f[i+1][Max(j+a[i+1], s[i]-j)] = 1,
f[i+1][Max(j, s[i]-j+a[i+1])] = 1;
} int ans = 0;
for(int i = 0; i <= s[n]; ++i)
if(f[n][i]) {
ans = i;
break;
}
printf("%d\n", ans);
return 0;
}
貌似直接取根号就是最优的,赛时看了一眼觉得像对钩函数就莽了一手三分...
E
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#define int long long
typedef double ld;
typedef long long ll;
typedef std::pair<long long, int> pli;
#define mp std::make_pair
#define pp push_back
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 200010;
const ll INF = 0x7fffffffffffffff;
std::priority_queue<pli>q;
int n, m, head[N], ent;
ll dis[N];
bool vis[N];
struct Edge {
int next, to, C, D;
}e[N << 1];
inline void add(int x, int y, int c, int d) {
e[++ent].to = y;
e[ent].C = c; e[ent].D = d;
e[ent].next = head[x]; head[x] = ent;
}
inline ld f(int p, int x, int t) {
return 1ll * t + 1.0 * e[p].D / (x + t + 1);
}
inline ll fl(int p, int x, int t) {
return 1ll * t + std::floor(1.0 * e[p].D / (x + t + 1));
}
ll calc(int p, int x) {
int l = 0, r = e[p].D;
ll ans = INF;
while(l <= r) {
int y = (r - l) / 3, mid1 = l + y, mid2 = mid1 + y;
ans = Min(ans, fl(p, x, l));
ans = Min(ans, fl(p, x, r));
ans = Min(ans, fl(p, x, mid1));
ans = Min(ans, fl(p, x, mid2));
if(f(p, x, mid1) >= f(p, x, mid2)) l = mid1+1;
else r = mid2-1;
}
ans = Min(ans, fl(p, x, l)); ans = Min(ans, fl(p, x, r));
ans = Min(ans, fl(p, x, l+1)); ans = Min(ans, fl(p, x, r+1));
if(l) ans = Min(ans, fl(p, x, l-1));
if(r) ans = Min(ans, fl(p, x, r-1));
return ans + e[p].C;
}
signed main() {
read(n); read(m);
for(int i = 1, u, v, c, d; i <= m; ++i) {
read(u); read(v); read(c); read(d);
add(u, v, c, d); add(v, u, c, d);
}
for(int i = 2; i <= n; ++i) dis[i] = INF;
q.push(mp(0, 1));
while(!q.empty()) {
int x = q.top().second; q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
ll cc = calc(i, dis[x]);
if(dis[v] > dis[x] + cc) {
dis[v] = dis[x] + cc;
q.push(mp(-dis[v], v));
}
}
}
printf("%lld\n", dis[n] == INF ? -1 : dis[n]);
return 0;
}