E. Equidistant
题意:有一颗树,有 m m m个特殊点,问是否存在一个点到 m m m个特殊点的距离相等
解法:换根 d p dp dp秒之,设 m x [ u ] , m n [ u ] mx[u],mn[u] mx[u],mn[u]分别为 u u u子树中距离 u u u最远的特殊点的距离和最近的特殊点的距离,首先一次 d f s dfs dfs搞定树 d p dp dp,接下来就是直接换根了,当一个点 u u u为根时 m x [ u ] = m n [ u ] mx[u]=mn[u] mx[u]=mn[u],那么这个点一定是合法的点
#include
#define pi pair
#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 n n个东西重量总和不超过 1 e 6 1e6 1e6,有 q q q次询问容量为 x x x的背包按顺序装东西至少需要多少个背包能装完所有东西
解法:我们预处理一下所有 s i z e size size的背包一次性能装几个东西,每次询问我们暴力去模拟一下即可,复杂度为调和级数
#include
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 n个东西的二维坐标和高度,你要建立一个高度最小的四棱锥,包含住这 n n n个东西,要求四棱锥底面是个和 x x x轴平行的正方形,四棱锥的四个面和二维平面呈45度角,求四棱锥中间坐标和最小的高度(整型数,如果为小数,向上取整)
解法:太南了,我们写个简单版的题:在 x x x轴上有 n n n个东西有高度,你要在 x x x轴上建立一个高度最小的等腰直角三角形,斜边和 x x x轴重合,要求三角形能覆盖住这 n n n个东西。这个题你会写吧?那对于原题意,我们可以忽视 y y y坐标转化成 x x x轴上找小的等腰三角形包含住它们,忽视 x x x坐标转化成 y y y轴上找最小的等腰直角三角形包含住它们,结合起来就是答案
#include
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,那么 u u u肯定不会有一条边走向 v v v,现在告诉你任意点 u u u到任意点 v v v的路径数模 10 10 10等于 a [ u ] [ v ] a[u][v] a[u][v],让你恢复这个有向图 ( n < = 500 ) (n<=500) (n<=500)
解法:假设 u , v u,v u,v有一条单向边直接相连,那么 d [ u ] [ v ] = 1 , d[u][v]=1, d[u][v]=1,我们从大到小枚举 u u u,然后从 u + 1 u+1 u+1到 n n n枚举 v v v,然后枚举 u , v u,v u,v之间的点 k k k,设 s u m sum sum为 u u u到 v v v的路径数,如果 d [ u ] [ k ] = 1 d[u][k]=1 d[u][k]=1,那么 s u m + = a [ k ] [ v ] sum+=a[k][v] sum+=a[k][v],如果最后 s u m ! = a [ u ] [ v ] sum!=a[u][v] sum!=a[u][v],那么 u , v u,v u,v肯定有单向边
#include
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("");
}
}