∆ 今天的热身赛的题很有质量!
∆ T1
题面:
现在,存在一组激光编号,需要从中挑选出来k个组成素数,并且可能存在多种方案,所以你需要知道至少要尝
试多少种组合才能破解这个机关,至于如何破解,那就是神兽的程序的问题了。
∆ 思路:
暴搜没得说
∆ 代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n, k, ans;
int a[20 + 5];
inline bool isPrime(int x)
{
for (int i = 2; i * i <= x; ++i)
if (!(x % i)) return false;
return true;
}
inline void DFS(int now, int sum, int tot)
{
if (tot == k)
{
if (isPrime(sum))
ans++;
return ;
}
if (now == n + 1)
return ;
DFS(now + 1, sum + a[now], tot + 1);
DFS(now + 1, sum, tot);
}
signed main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)scanf("%d",&a[i]);
DFS(1, 0, 0);
printf("%d\n", ans);
return 0;
}
∆ T2
题面:
这里的防御系统要求所有的资料会在第k次全部弹出,但是每份资料的重量可能不同,且必须按照既定的顺序选择每一次弹出的资料,每一次至少弹出一份资料,上不封顶,但是神兽希望最重的那组资料重量在他们的承受范围之内,所以要求最重的那组资料尽可能轻。
∆ 思路
虽然读题读了很久,但还好看出了这是一道二分答案的题目
∆ 代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const long long MAXN = 1e6 + 10;
long long n, k;
long long a[MAXN];
long long check(long long rhs) {
long long res = 0;
long long tot = 0;
for (long long i = 1; i <= n; ++i) {
if (tot + a[i] > rhs) {
tot = 0;
res++;
}
tot += a[i];
}
return res + 1;
}
signed main()
{
scanf("%lld%lld", &n, &k);
long long l = 0, r = 1e16;
for (long long i = 1; i <= n; i++)
scanf("%lld", &a[i]),
l = max(l, a[i]);
while (l < r)
{
long long mid = (l + r) / 2;
if (check(mid) <= k) r = mid;
else l = mid + 1;
}
printf("%lld", l);
return 0;
}
∆ T3
∆ 题面
神兽思考片刻,突然想到了自己设计的一套程序就是针对自动化武器的,而且如果这些武器联网,还能达到传播歼灭所有网内系统的效果,但是每次传播都需要神兽亲自完成,并花费大量时间,当然每次部署一个武器也会花费大量时间,神兽可以选择联网系统中的一部分系统进行部署,剩下的可以由他来传播(由于只能由神兽完成部署和传播,所以所有操作不能同时进行)
∆ 思路
这道题一看就是最小生成树。板子题没什么可讲的
∆ 代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <queue>
using namespace std;
const int MAXN = 90000 + 5;
int cost[MAXN];
struct Edge
{
int u;
int v;
int w;
bool operator < (const Edge &rhs) const { return w < rhs.w; }
} edge[MAXN];
int fa[MAXN];
inline void init(int n)
{
for (int i = 0; i < n; ++i) fa[i] = i;
}
inline int find(int x)
{
if (x ^ fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
inline void union_(int x, int y)
{
int u = find(x), v = find(y);
if (u ^ v) fa[u] = v;
}
int n, m;
signed main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
int cost;
scanf("%d", &cost);
edge[m++] = Edge{0, i, cost};
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
{
int cost;
scanf("%d", &cost);
if (j > i) edge[m++] = Edge{i, j, cost};
}
++n;
sort(edge, edge + m);
init(n);
int ans = 0, src = 0;
for (int i = 0; i < m; ++i)
{
if (find(edge[i].u) != find(edge[i].v))
{
union_(edge[i].u, edge[i].v);
ans += edge[i].w;
src++;
if (src == n - 1) break;
}
}
printf("%d", ans);
return 0;
}
∆ T4
∆ 题面
小L在上学路上不幸掉入了一口井深D英尺的深井中,不幸的是,他只能靠吃掉到井里的东西来维持生命了,但幸运的是,每隔一段时间小T就会往井里丢东西,小L可以选择用这些东西垫在脚下尝试着爬出井口或者吃掉它们来续命,被垫在脚下的东西就不能再吃了,当然吃过的东西也不能再垫在脚下。当小L的高度和井口高度一样高的时候,他就可以爬出井口了。小L预先知道了一共会有N个东西被丢下来,并且他还知道了他们的掉落时间,高度以及能够维持生命的时间长度。 一开始,小L体内的能量能够维持10个单位时间的生命。
∆ 思路
` 这是一道dp题。似乎贪心也能过??
设dp[i][j]为第i个物品掉下时,小L的高度为j时的最大生命值
可推出转移方程:
dp[i + 1][j + A[i].height] = max(dp[i + 1][j + A[i].height], dp[i][j] - qq);
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] - qq + A[i].life_num);
其中qq为后一个物品掉落的时间与当前凋落物出现时间差 `
∆ 代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <queue>
using namespace std;
const int MAXN = 1000 + 5;
int High, n;
int dp[MAXN][MAXN / 3];
struct node
{
int app_tim;
int life_num;
int height;
bool operator < (const node &rhs) const { return app_tim < rhs.app_tim; }
} A[MAXN];
signed main()
{
scanf("%d%d", &High, &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &A[i].app_tim);
scanf("%d", &A[i].life_num);
scanf("%d", &A[i].height);
}
sort(A + 1, A + 1 + n);
memset(dp, -1, sizeof dp);
dp[0][0] = 10;
int ans = 0;
for (int i = 0; i <= n; ++i)
{
int qq = A[i + 1].app_tim - A[i].app_tim;
for (int j = 0; j <= High; ++j)
{
if (dp[i][j] < 0) continue;
dp[i + 1][j + A[i].height] = max(dp[i + 1][j + A[i].height], dp[i][j] - qq);
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] - qq + A[i].life_num);
if (j + A[i].height >= High)
return printf("%d\n", A[i].app_tim) & 0;
}
if (dp[i][0] >= 0)
ans = max(ans, dp[i][0] + A[i].life_num + A[i].app_tim);
}
printf("%d\n", ans);
return 0;
}
∆ T5
∆ 思路
首先这肯定是一个图,因为A, B, C点的位置不确定。 所以我们先跑一个最短路确定C点,然后再跑两个最短路确定B, C点的位置,最后统计A~C和B~C谁的距离比较小输出即可
∆ 代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <cctype>
#include <climits>
#define Int long long
#define oo LONG_LONG_MAX
using namespace std;
const int MAXN = 200000 + 5;
int n, m;
struct Edge
{
int v;
Int w;
};
vector<Edge> G[MAXN];
bool vis[MAXN];
Int dis[3][MAXN];
inline void pushEdge(int u, int v, Int w)
{
G[u].push_back(Edge{v, w});
G[v].push_back(Edge{u, w});
}
inline void init(int k)
{
for (int i = 1; i <= n; ++i)
{
dis[k][i] = oo;
vis[i] = 0;
}
}
inline void BFS(int s, int t)
{
init(s);
dis[s][t] = 0;
vis[t] = 1;
queue<int> Q;
Q.push(t);
while (!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = false;
for (int i = 0; i < (int)G[u].size(); ++i)
{
int v = G[u][i].v;
int w = G[u][i].w;
if (dis[s][v] > dis[s][u] + w)
{
dis[s][v] = dis[s][u] + w;
if (!vis[v])
{
vis[v] = true;
Q.push(v);
}
}
}
}
}
signed main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i)
{
int u, v;
Int w;
scanf("%d%d%lld", &u, &v, &w);
pushEdge(u, v, w);
}
Int ans1 = 0;
int Node1 = 0;
BFS(0, 1);
for (int i = 1; i <= n; ++i)
if (dis[0][i] > ans1)
ans1 = dis[0][i],
Node1 = i;
BFS(1, Node1);
Int ans2 = 0;
int Node2 = 0;
for (int i = 1; i <= n; ++i)
if (dis[1][i] > ans2)
ans2 = dis[1][i],
Node2 = i;
BFS(2, Node2);
Int ans3 = 0;
for (int i = 1; i <= n; ++i)
if (i != Node1 && i != Node2)
ans3 = max(ans3, min(dis[1][i], dis[2][i]));
printf("%lld\n", ans3 + ans2);
}
∆ T7
∆ 思路
` 这道题...做过的吧?
没错就是那个泥泞的牧场。
没有做的同学看了这篇题解估计两道题都能做。
首先我们从泥泞的牧场讲起:
此题的难点在于如何去建图。
很显然我们需要把行和列分别当成二分图的两部分 。 所以我们可以分别把一个点行的连通块和列的连通块处理出来。
每次发现一个点就把编一个号,然后就可以把图构建出来了!
T7只是在泥泞的牧场上加了一个判断而已 `
∆ 代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 1000 + 5;
int n, m, R, C;
char str[MAXN][MAXN];
int G[MAXN][MAXN], match[MAXN];
int row[MAXN][MAXN];
int vis[MAXN], col[MAXN][MAXN];
inline bool DFS(int k)
{
for (int i = 1; i <= C; ++i)
{
if (G[k][i] && !vis[i])
{
vis[i] = true;
if (!match[i] || DFS(match[i]))
return (match[i] = k) * 0 + 1;
}
}
return 0;
}
signed main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%s", str[i] + 1);
int t_sum = 0;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (str[i][j] == '*')
{
++t_sum;
while ((str[i][j] == 'x' || str[i][j] == '*') && j <= m) row[i][j] = t_sum, ++j;
}
}
}
R = t_sum;
t_sum = 0;
for (int j = 1; j <= m; ++j)
{
for (int i = 1; i <= n; ++i)
{
if (str[i][j] == '*')
{
++t_sum;
while ((str[i][j] == 'x' || str[i][j] == '*') && i <= n) col[i][j] = t_sum, ++i;
}
}
}
C = t_sum;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (str[i][j] == '*')
G[row[i][j]][col[i][j]] = 1;
int ans = 0;
for (int i = 1; i <= R; ++i)
{
memset(vis, 0, sizeof vis);
if (DFS(i)) ans++;
}
printf("%d\n", ans);
}
∆ T7
∆ 思路
这题似乎是一个分治??
但经过观察我们可以发现以下规律:
如果最后的温度大于等于最大的温度值,输出possible和最后的温度
如果最后的温度不大于最小的温度值,输出possible和最小值
否则输出Impossible。
∆ 代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n;
double T, C;
double t, c;
const auto MAX = 1e17;
signed main()
{
double _min = MAX, _max = -MAX;
scanf("%d", &n);
scanf("%lf%lf", &T, &C);
for (int i = 1; i <= n; ++i)
{
scanf("%lf%lf", &t, &c);
T = (T * C + t * c) / (c + C);
C += c;
_min = min(_min, t);
_max = max(_max, t);
}
if (T >= _max) printf("Possible\n%.4lf", T);
else if (T <= _min) printf("Possible\n%.4lf", _min);
else puts("Impossible");
return 0;
}