A. 越狱
题意: 给定一个长度为的序列,找到一个最小的正整数,使得最大化。 数据范围: 对于,都有
题解: 找到排名为的数即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N], n;
int c[N];
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
nth_element(a, a + n / 2 - 1, a + n);
printf("%d %d\n", n / 2, a[n / 2 - 1] + 1);
return 0;
}
B. 物流
题意: A地有 吨货物,B地有 吨货物,C地需要 吨货物,D地需要 吨货物。吨货物从A到C花 的代价,从A到D花 的代价,从B到C花 的代价,从B到D花 的代价。求最小代价。 注意,从A/B地到C/D地的货物是一吨一吨运输的,也就是说你可以选择A/B地的一部分货物来满足C/D地的一部分需求,但是最终C/D的需求必须全部满足。 输入只含有正整数。
数据范围: 组数据,
题解: 考虑 如果 那么必然是优先处理掉,这样使得少一点支出, 所以这里只需要考虑优先处理掉中的一种即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(int ca) {
ll a, b, c, d, v[5];
scanf("%lld%lld%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &v[1], &v[2], &v[3], &v[4]);
ll res = 9e18;
// a -> c
{
if(a >= c) {
res = min(res, c * v[1] + (a - c) * v[2] + b * v[4]); // a->c, a->d, b->d
} else if(a < c) {
res = min(res, a * v[1] + (c - a) * v[3] + d * v[4]); // a->c, b->c, b->d
}
}
// a -> d
{
if(a >= d) {
res = min(res, d * v[2] + (a - d) * v[1] + b * v[3]); // a->d, a->c, b->d
} else if(a < d) {
res = min(res, a * v[2] + (d - a) * v[4] + c * v[3]); // a->d, b->d, b->c
}
}
// b -> c
{
if(b >= c) {
res = min(res, c * v[3] + (b - c) * v[4] + a * v[2]); // b->c, b->d, a->d
} else if(b < c) {
res = min(res, b * v[3] + (c - b) * v[1] + d * v[2]); // b->c, a->c, a->d
}
}
// b -> d
{
if(b >= d) {
res = min(res, d * v[4] + (b - d) * v[3] + a * v[1]); // b->d, b->c, a->c
} else if(b < d) {
res = min(res, b * v[4] + (d - b) * v[2] + c * v[1]); // b->d, a->d, a->c
}
}
printf("%lld\n", res);
}
int main()
{
int T = 1;
scanf("%d", &T);
for(int i = 1; i <= T; ++i) solve(i);
return 0;
}
C. 数的和与积
题意: 给定一个 ,请你将 到 中的所有整数划分为两个集合,使得第一个集合里的数的积等于第二个集合里的数的和。 输出第一个集合的数。无解输出 。
数据范围: 组数据,
题解: 模拟几个样例可以发现: 和时无解,时可以分为 sum组,mul组 从开始, 存在有:
5
mul: 1 2 4
6
mul: 1 2 6
7
mul: 1 3 6
8
mul: 1 3 8
9
mul: 1 4 8
10
mul: 1 4 10
11
mul: 1 5 10
12
mul: 1 5 12
可以发现三个数字依次为:
证明: 移项: 因此只要找到和满足
必然是一个整数, 当是偶数, 和 ,
当是奇数, 和 ,
综合起来就是
当时,,,显然不合法 当时,,因为本身就需要选择一个,所以这也不合法 当时,,此时再选择一个,这里就不合法了,但是可以只选择一个,这里的情况不符合公式,需要特判。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
void solve() {
scanf("%d", &n);
if(n == 2 || n == 4) {
puts("-1");
return ;
}
if(n == 3) {
puts("1\n3");
return ;
}
printf("3\n1 %d %d\n", (n - 1) / 2, (n % 2 ? n - 1 : n));
}
int main()
{
int T = 1;
scanf("%d", &T);
for(int i = 1; i <= T; ++i) solve();
return 0;
}
D. 礼物
题意: 给定一棵个点的树,确定一个根使得 最大。 题目保证答案唯一。 数据范围:
题解: 换根 这里先考虑以为根进行,求出这样的一棵有根树的子树大小。 考虑以为根的有根树
- 表示的子树中的任意两点的LCA值之和
- 表示的子树大小,包括
- 可以注意到的是树上任意一条边的两点和为根时,两者的 差别在于:
- 以为根时,
v及其子树
到u
、oth子树
、u的父亲fa对应的除去子树u的剩余子树
对应的权值为: - 以为根时,
u
、oth子树
、u的父亲fa对应的除去子树u的剩余子树
到v及其子树
对应的权值为: 两者的其余部分是完全相同的,分别为:
- 以为根时,
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000010;
const int M = N << 1;
int h[N], e[M], ne[M], idx;
int n, id;
ll sum, ans;
ll siz[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs1(int u, int fa) {
siz[u] = 1;
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(v != fa) {
dfs1(v, u);
sum += siz[u] * siz[v] * u;
siz[u] += siz[v];
}
}
}
void dfs2(int u, int fa) {
if(sum > ans) {
ans = sum;
id = u;
}
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(v != fa) {
ll temp = siz[v] * (n - siz[v]) * (u - v);
sum -= temp;
dfs2(v, u);
sum += temp;
}
}
}
void solve(int ca) {
scanf("%d", &n);
memset(h, -1, (n + 1) * sizeof(int));
idx = 0;
for(int i = 1; i < n; ++i) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs1(1, -1);
ans = 0;
dfs2(1, -1);
printf("%d %lld\n", id, ans * 2 + 1ll * n * (n + 1) / 2);
}
int main()
{
int T = 1;
// scanf("%d", &T);
for(int i = 1; i <= T; ++i) solve(i);
return 0;
}