- NEKO's Maze Game
- 题意
- 题解
- 代码
- Aroma's Search
- 题意
- 题解
- 代码
- Xenon's Attack on the Gangs
- 题意
- 题解
- 代码
NEKO's Maze Game
题目链接 https://codeforces.com/contest/1292/problem/A
题意
给出一个 2xN 的地图,每一时刻都有一个位置翻转状态(可走和不可走变换),输出每时刻是否可以从起点走到终点。
题解
地图只有 2xN,两个跨行相邻的位置不可走从起点就走不到终点。
[o][2][3][4][o]
[o][o][1][o][o]
如果 1 位置,2,3,4位置一个位置不可走都会产生一堵“墙”。统计产生的全部墙数,没墙时可以走到终点,否则不能走到。
代码
#include <cstdio>
using namespace std;
int N, Q;
int cnt;
bool die[2][100010];
void cg(int r, int c)
{
int flag;
if (die[r][c] == false)
{
flag = 1;
die[r][c] = true;
}
else
{
flag = -1;
die[r][c] = false;
}
for (int i = -1; i <= 1; i++)
{
if (die[r^1][c+i])
cnt += flag;
}
}
int main()
{
scanf("%d %d", &N, &Q);
int r, c;
for (int i = 1; i <= Q; i++)
{
scanf("%d %d", &r, &c);
r--;
cg(r, c);
if (cnt)
{
printf("No\n");
}
else
{
printf("Yes\n");
}
}
return 0;
}
Aroma's Search
题目链接 https://codeforces.com/contest/1292/problem/B
题意
二维平面上按照规则产生一些得分点,问时间 t 内,从起点出发最多可以得到多少分。
??????????1+????,??????????1+????
得分点生成规则,给出 \((x_0,y_0)\),其他点 \((a_x x_{i-1} +b_x, a_y y_{i-1} +b_y)\)。
题解
按照生成规则,显然最多生成 64 个得分点,用平方算法枚举经过的得分段两端即可。
注意坐标较大,生成得分点的时候注意坐标太大的点不用生成,防止数据溢出。
代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
#define MAX 10000000000000000LL
typedef long long ll;
ll dis(ll x1, ll y1, ll x2, ll y2)
{
return llabs(x1-x2) + llabs(y1-y2);
}
ll Ax, Ay, Bx, By;
ll Xs, Ys, T;
ll pts[100][2];
int ptt;
ll sm[100];
int main()
{
scanf("%lld %lld %lld %lld %lld %lld",
&pts[0][0], &pts[0][1], &Ax, &Ay, &Bx, &By);
scanf("%lld %lld %lld", &Xs, &Ys, &T);
for (ptt = 1; ptt < 100; ptt++)
{
pts[ptt][0] = Ax*pts[ptt-1][0] + Bx;
pts[ptt][1] = Ay*pts[ptt-1][1] + By;
if (dis(pts[ptt][0], pts[ptt][1], Xs, Ys) > MAX*2)
break;
}
for (int i = 1; i < ptt; i++)
{
sm[i] = dis(pts[i][0], pts[i][1], pts[i-1][0], pts[i-1][1]);
sm[i] += sm[i-1];
}
int ans = 0;
ll K;
for (int i = 0; i < ptt; i++) {
for (int j = i; j < ptt; j++) {
K = min(dis(pts[i][0], pts[i][1], Xs, Ys),
dis(pts[j][0], pts[j][1], Xs, Ys))
+ (sm[j] - sm[i]);
if (K <= T) {
ans = max(ans, j-i+1);
}
}
}
printf("%d\n", ans);
return 0;
}
Xenon's Attack on the Gangs
题目链接 https://codeforces.com/contest/1292/problem/C
题意
给出 N 个结点的树,定义
\[ S = \sum_{1 \leq u < v \leq n}mex(u, v) \]
\(mex(u, v)\) 定义为,u 到 v 的路径权值中不包含的最小自然数。
将权值 0 ~ n-2 分配到每条边上,每条边上权值不同,求 S 的最大值。
题解
从另一个方向维护答案:
\[ \begin{align}
S =& \sum_{1 \leq u < v \leq n}mex(u, v) \label{C1} \\
=& \sum_{1 \leq x \leq n} \sum_{mex(u,v)=x}x \label{C2} \\
=& \sum_{1 \leq x \leq n} \sum_{mex(u,v) \geq x} 1 \label{C3}
\end{align} \]
假设树中全部mex值为1,2,3,5,5
则 \(\ref{C1}\) 式是将每条路径上的mex值求和:
- 1
-- 2
--- 3
----- 5
----- 5
S = 1+2+3+5+5
\(\ref{C3}\) 式是从另一个方向求和:
| 1
|| 2
||| 3
||||| 5
||||| 5
54322
S = 5+4+3+2+2
显然两式等价。
由 mex 的特点可知,0~k-1 一定在长度为 K 的一条链上,且mex>=K的数量取决于链两端点的位置,与0~k-1的顺序无关。
可以使用 \(dp[u][v]\) 表示从\(u\)到\(v\)的一条路径上放置0~k-1时的S的最大值。
\[dp[u][v] = sub(u,v)sub(v,u) + max(dp[par(v,u)][v], dp[u][par(u,v)])\]
其中 \(sub(u,v)\) 是以u为根的v的子树大小,\(par(u,v)\) 是以\(u\)为根\(v\)的父结点
代码
#include <cstdio>
#include <vector>
using namespace std;
#define Nmax 3010
int N;
vector<int> gp[Nmax];
void init()
{
scanf("%d", &N);
int a, b;
for (int i = 1; i < N; i++)
{
scanf("%d %d", &a, &b);
gp[a].push_back(b);
gp[b].push_back(a);
}
}
int par[Nmax][Nmax];
int sub[Nmax][Nmax];
int root;
void DFS(int x, int fa)
{
int t;
sub[root][x] = 1;
par[root][x] = fa;
for (int i = 0; i < gp[x].size(); i++)
{
t = gp[x][i];
if (t == fa)
continue;
DFS(t, x);
sub[root][x] += sub[root][t];
}
}
long long dp[Nmax][Nmax];
long long DP(int x, int y)
{
if (x == y)
return 0;
if (dp[x][y])
return dp[x][y];
if (dp[y][x])
return dp[x][y] = dp[y][x];
dp[x][y] = sub[x][y]*sub[y][x] + max(DP(par[y][x], y), DP(x, par[x][y]));
return dp[x][y];
}
void work()
{
for (int i = 1; i <= N; i++)
{
root = i;
DFS(i, 0);
}
long long ans = 0;
for (int i = 1; i <= N; i++)
{
for (int j = i+1; j <= N; j++)
{
ans = max(ans, DP(i, j));
}
}
printf("%lld\n", ans);
}
int main()
{
init();
work();
return 0;
}
原文地址:https://www.cnblogs.com/KZNS/p/codeforces-round-614.html