Solved:4/10(A、D、E、G)
Rank:34/134
UpSolving:5/10(A、C、D、E、G)
https://ac.nowcoder.com/acm/contest/4114
A、黑色气球
乱搞
#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int a[1005][1005];
int main()
{
int n;
sc("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
sc("%d", &a[i][j]);
if (n == 2)
{
pr("1 %d", a[1][2] - 1);
return 0;
}
ll ans = (a[1][2] + a[1][3] - a[2][3]) / 2;
pr("%lld", ans);
for (int i = 2; i <= n; i++)
{
pr(" %lld", a[1][i] - ans);
}
}
C、无向图定向
给定无向图,给每条边定向,求最短的最长路
考虑 k 染色问题,假如能用 k 种颜色对图中的点进行染色,且方向限制为颜色小的指向颜色大的(自己定义即可),显然这样的图不会有环,并且最长路的长度一定不会大于 k.
#include <iostream>
#include <string.h>
using namespace std;
int G[105][105];
int fangjian[105][105], cnt[105];
int n, m, ans;
void dfs(int cur, int tol) {
if(tol >= ans) return;
if(cur > n) {
ans = min(ans, tol);
return;
}
for(int i = 0; i < tol; i++) {
int f = 1;
for(int j = 0; j < cnt[i]; j++) {
int t = fangjian[i][j];
if(G[cur][t]) {
f = 0;
break;
}
}
if(f) {
fangjian[i][cnt[i]++] = cur;
dfs(cur+1, tol);
--cnt[i];
}
}
fangjian[tol][cnt[tol]++] = cur;
dfs(cur+1, tol+1);
--cnt[tol];
}
int main() {
cin>>n>>m;
memset(G, 0, sizeof(G));
int a, b;
for(int i = 0; i < m; i++) {
cin>>a>>b;
G[a][b] = G[b][a] = 1;
}
memset(cnt, 0, sizeof(cnt));
ans = 105;
dfs(1, 0);
cout<<ans-1<<endl;
return 0;
}
D、求和
https://blog.csdn.net/qq_41608020/article/details/103980636
E、棋技哥
考虑除了第一行第一列的其他位置,都可以通过四次反转使那个位置变成白色(考虑类似二维前缀和的四次翻转),所以能不能赢取决于第一行第一列是黑色还是白色。
#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
char a[505];
int main()
{
int T, n, m;
sc("%d", &T);
while (T--)
{
sc("%d%d", &n, &m);
bool f = false;
sc("%s", a + 1);
if (a[1] == '1')
f = true;
else
f = false;
for (int i = 2; i <= n; i++)
sc("%s", a + 1);
if (f == true)
pr("call\n");
else
pr("aoligei\n");
}
}
G、火山哥周游世界
有 k 个关键点,求从任意一点开始,走遍 k 个关键点的最短路径长度
要求的最短路径实际上就是根节点到每个分支最远点距离的两倍减去根节点到最远点的距离。考虑换根dp,我们很容易求出以每个点为根节点到每个分支最远点距离,我们需要考虑的就是这个点为根,最远点的距离,在换根的同时,记录这个点向上的最远点就可以了,实际上就是这个点的爸爸到除了这个儿子分支的其他儿子分支的最远点的距离。
#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 5e5 + 5;
struct edge
{
int to;
ll w;
int nex;
}e[MAXN * 2];
int head[MAXN], tot;
void init()
{
memset(head, -1, sizeof head);
tot = 1;
}
void add(int in, int to, ll w)
{
e[tot] = edge{ to,w,head[in] };
head[in] = tot++;
}
int n, k;
int sz[MAXN], son[MAXN];
ll maxn1[MAXN], maxn2[MAXN], dp[MAXN];
ll up[MAXN];//向上最远距离(可以通过父节点到达的最远距离
void dfs1(int u, int fa)
{
for (int i = head[u]; i + 1; i = e[i].nex)
{
int v = e[i].to;
if (v == fa)
continue;
dfs1(v, u);
sz[u] += sz[v];
if (sz[v])
{
dp[u] += dp[v] + 2 * e[i].w;
if (maxn1[v] + e[i].w > maxn1[u])
{
maxn2[u] = maxn1[u];
maxn1[u] = maxn1[v] + e[i].w;
son[u] = v;//记录向下最远儿子
}
else if (maxn1[v] + e[i].w > maxn2[u])
maxn2[u] = maxn1[v] + e[i].w;
}
}
}
void dfs2(int u, int fa)
{
for (int i = head[u]; i + 1; i = e[i].nex)
{
int v = e[i].to;
if (v == fa)
continue;
if (sz[v] != k)
{
if (v == son[u])//如果这个点是向下最远儿子,不能用这个分治的maxn来更新
up[v] = e[i].w + max(up[u], maxn2[u]);
else//反之,用最远maxn来更新
up[v] = e[i].w + max(up[u], maxn1[u]);
}
dp[v] = dp[u];
if (sz[v] != 0)//往下走?
dp[v] -= e[i].w * 2;
if (sz[v] != k)//往上走?
dp[v] += e[i].w * 2;
dfs2(v, u);
}
}
int main()
{
init();
sc("%d%d", &n, &k);
for (int i = 1; i < n; i++)
{
int a, b; ll c;
sc("%d%d%lld", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
for (int i = 1; i <= k; i++)
{
int a;
sc("%d", &a);
sz[a]++;
}
dfs1(1, 0);
dfs2(1, 0);
for (int i = 1; i <= n; i++)
pr("%lld\n", dp[i] - max(maxn1[i], up[i]));
}