E. Equidistant
题意:有一颗树,有
m个特殊点,问是否存在一个点到
m个特殊点的距离相等
解法:换根
dp秒之,设
mx[u],mn[u]分别为
u子树中距离
u最远的特殊点的距离和最近的特殊点的距离,首先一次
dfs搞定树
dp,接下来就是直接换根了,当一个点
u为根时
mx[u]=mn[u],那么这个点一定是合法的点
#include<bits/stdc++.h>
#define pi pair<int, int>
#define mk make_pair
using namespace std;
const int maxn = 2e5 + 10, inf = 1e9;
vector<int> G[maxn];
vector<pi> s[maxn];
int mx[maxn], mn[maxn], cat[maxn], jie, n;
void dfs(int u, int fa) {
if (cat[u])
mx[u] = mn[u] = 0;
else
mx[u] = -inf, mn[u] = inf;
for (auto v : G[u])
if (v != fa) {
dfs(v, u);
mx[u] = max(mx[u], mx[v] + 1);
mn[u] = min(mn[u], mn[v] + 1);
}
}
void dfs2(int u, int fa) {
if (jie)
return;
if (cat[u])
mx[u] = mn[u] = 0;
else
mx[u] = -inf, mn[u] = inf;
s[u].push_back(mk(mx[u],mn[u]));
for (auto v : G[u]) {
mx[u] = max(mx[u], mx[v] + 1);
mn[u] = min(mn[u], mn[v] + 1);
s[u].push_back(mk(mx[u], mn[u]));
}
if (mx[u] == mn[u]) {
jie = u;
return;
}
int Mx = -inf, Mn = inf;
for (int i = G[u].size() - 1; ~i; i--) {
int v = G[u][i];
mx[u] = max(s[u][i].first, Mx);
mn[u] = min(s[u][i].second, Mn);
Mx = max(Mx, mx[v] + 1);
Mn = min(Mn, mn[v] + 1);
if (v != fa)
dfs2(v, u);
}
}
int main()
{
int m, u, v;
scanf("%d%d", &n, &m);
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = 1; i <= m; i++) {
scanf("%d", &u);
cat[u] = v;
}
dfs(1, 0);
dfs2(1, 0);
if (jie)
printf("YES\n%d\n", jie);
else
puts("NO");
}
H. High Load Database
题意:有
n个东西重量总和不超过
1e6,有
q次询问容量为
x的背包按顺序装东西至少需要多少个背包能装完所有东西
解法:我们预处理一下所有
size的背包一次性能装几个东西,每次询问我们暴力去模拟一下即可,复杂度为调和级数
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5, N = 1e6;
int a[maxn], p[maxn], d[maxn], sum[maxn], mx, n;
int gao(int x) {
if (x < mx)
return -1;
if (d[x])
return d[x];
int res = 0, i = 0;
while (i < n) {
res += x;
res = min(res, N);
i = p[res];
res = sum[i];
d[x]++;
}
return d[x];
}
int main()
{
int q, x;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
mx = max(mx, a[i]);
sum[i] = sum[i - 1] + a[i];
for (int j = sum[i - 1]; j < sum[i]; j++)
p[j] = i - 1;
}
for (int i = sum[n]; i <= N; i++)
p[i] = n;
scanf("%d", &q);
while (q--) {
scanf("%d", &x);
if (gao(x) != -1)
printf("%d\n", gao(x));
else
printf("Impossible\n");
}
}
I. Ideal Pyramid
题意:给出
n个东西的二维坐标和高度,你要建立一个高度最小的四棱锥,包含住这
n个东西,要求四棱锥底面是个和
x轴平行的正方形,四棱锥的四个面和二维平面呈45度角,求四棱锥中间坐标和最小的高度(整型数,如果为小数,向上取整)
解法:太南了,我们写个简单版的题:在
x轴上有
n个东西有高度,你要在
x轴上建立一个高度最小的等腰直角三角形,斜边和
x轴重合,要求三角形能覆盖住这
n个东西。这个题你会写吧?那对于原题意,我们可以忽视
y坐标转化成
x轴上找小的等腰三角形包含住它们,忽视
x坐标转化成
y轴上找最小的等腰直角三角形包含住它们,结合起来就是答案
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
struct node
{
int x, y, h;
} a[maxn];
int main()
{
int n, L1 = 2e9, L2 = 2e9, R1 = -2e9, R2 = -2e9, x, y;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].x >> a[i].y >> a[i].h;
for (int i = 1; i <= n; i++)
{
L1 = min(L1, a[i].x - a[i].h);
R1 = max(R1, a[i].x + a[i].h);
L2 = min(L2, a[i].y - a[i].h);
R2 = max(R2, a[i].y + a[i].h);
}
x = (L1 + R1) / 2;
y = (L2 + R2) / 2;
int h = max(x - L1, y - L2);
int h2 = max(R1 - x, R2 - y);
h = max(h, h2);
printf("%d %d %d\n", (L1 + R1) / 2, (L2 + R2) / 2, h);
}
J. Just the Last Digit
题意:有一个有向图,满足如果
u>=v,那么
u肯定不会有一条边走向
v,现在告诉你任意点
u到任意点
v的路径数模
10等于
a[u][v],让你恢复这个有向图
(n<=500)
解法:假设
u,v有一条单向边直接相连,那么
d[u][v]=1,我们从大到小枚举
u,然后从
u+1到
n枚举
v,然后枚举
u,v之间的点
k,设
sum为
u到
v的路径数,如果
d[u][k]=1,那么
sum+=a[k][v],如果最后
sum!=a[u][v],那么
u,v肯定有单向边
#include<bits/stdc++.h>
using namespace std;
const int maxn = 505;
char s[maxn][maxn];
int a[maxn][maxn];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", s[i] + 1);
for (int j = 1; j <= n; j++)
s[i][j] -= '0';
}
for (int i = n - 1; i; i--)
for (int j = i + 1; j <= n; j++) {
int cat = 0;
for (int k = i + 1; k < j; k++)
cat = (cat + s[k][j] * a[i][k]) % 10;
if (cat != s[i][j])
a[i][j] = 1;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
printf("%d", a[i][j]);
puts("");
}
}