B Eezie and Pie
题意:给定一个 个点的树,第 个节点可以到达其第 级祖先。问每个点能被几个点到达。。
解法:树上差分。对于每个点,其贡献在于从它往上 个节点的一条链。倒过来从儿子往父亲差分,那么只需要给当前节点打上 标记, 级祖先打上 标记即可。总时间复杂度 。
#include <bits/stdc++.h>
#define fp(i, a, b) for (int i = a, i##_ = (b) + 1; i < i##_; ++i)
using namespace std;
const int N = 2e6 + 5;
using ll = int64_t;
int n, d[N], sz[N], dep[N], fa[N][21];
vector<int> G[N];
int get(int u, int k) {
for (int i = 20; ~i; --i)
if (k >= dep[u] - dep[fa[u][i]])
k -= dep[u] - dep[fa[u][i]], u = fa[u][i];
return u;
}
void dfs(int u, int p) {
dep[u] = dep[p] + 1;
fa[u][0] = p, sz[u] = 1;
fp(i, 1, 20) fa[u][i] = fa[fa[u][i - 1]][i - 1];
--sz[get(u, d[u] + 1)];
for (auto v : G[u])
if (v != p)
dfs(v, u), sz[u] += sz[v];
}
void Solve() {
scanf("%d", &n);
for (int u, v, i = 1; i < n; ++i)
scanf("%d%d", &u, &v),
G[u].push_back(v), G[v].push_back(u);
fp(i, 1, n) scanf("%d", d + i);
dfs(1, 0);
fp(i, 1, n) printf("%d ", sz[i]);
}
int main() {
int t = 1;
while (t--) Solve();
return 0;
}
G Icon Design
题意:画出给定缩放尺寸的 NFLS
字符画。
解法:找出定位点,暴力模拟。
#include <bits/stdc++.h>
using namespace std;
char a[30][1001];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= 4 * n + 5;i++)
for (int j = 1; j <= 13 * n + 19;j++)
a[i][j] = '.';
for (int i = 1; i <= 13 * n + 19; i++)
a[1][i] = a[4 * n + 5][i] = '*';
for (int i = 1; i <= 4 * n + 5;i++)
a[i][1] = a[i][13 * n + 19] = '*';
for (int x = n + 2, y = n + 3, i = 1; i <= 2 * n + 3;i++, x++, y++)
a[x][y] = a[x][n + 3] = a[x][3 * n + 5] = '@';
for (int y = 4 * n + 7, i = 1; i <= 2 * n + 3;i++, y++)
a[n + 2][y] = a[2 * n + 3][y] = '@';
for (int i = 1, x = n + 2; i <= 2 * n + 3;i++, x++)
a[x][4 * n + 7] = '@';
for (int i = 1, x = n + 2; i <= 2 * n + 3;i++, x++)
a[x][7 * n + 11] = '@';
for (int i = 1, y = 7 * n + 11; i <= 2 * n + 3;i++, y++)
a[3 * n + 4][y] = '@';
for (int i = 1, x = 10 * n + 15; i <= 2 * n + 3;i++, x++)
a[n + 2][x] = a[2 * n + 3][x] = a[3 * n + 4][x] = '@';
for (int i = 1, y = n + 2; i <= n + 1;y++, i++)
a[y][10 * n + 15] = '@';
for (int i = 1, y = 2 * n + 3; i <= n + 1; i++, y++)
a[y][12 * n + 17] = '@';
for (int i = 1; i <= 4 * n + 5; i++)
printf("%s\n", a[i] + 1);
return 0;
}
J Number Game
题意:给定三个数字 ,一次操作可以令 或 。问 能否变成 。, 组测试,。
题意:显然不会连续进行两次 ,否则等于没有操作,因而一定是两个操作交替进行的。设初始值为 :
- :;
- :;
- :;
- :;
- …
可以注意到最终的 会与 差一个 的倍数,具体倍数的正负与先进行第一个操作与第二个操作有关。因而最终只需要判断 与 的整除关系即可。当然 也可以先进行一次操作变成 ,因而再判断一次即可。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d", &t);
long long A, B, C, x;
while(t--)
{
scanf("%lld%lld%lld%lld", &A, &B, &C, &x);
if (A == 2 * B)
{
if (x == C || x == B - C)
printf("Yes\n");
else
printf("No\n");
continue;
}
bool flag = 0;
if ((x - (B - C)) % (A - 2 * B) == 0)
flag = 1;
if ((x - C) % (A - 2 * B) == 0)
flag = 1;
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
M Z-Game on grid
题意:给定一个 的棋盘,上面有 A,B,.
三种字符。有一个棋子从 出发,如果走到 A
的格子则 先手获胜,走到 B
的格子则后手获胜,走到 且为 .
则为平局。若一个棋子在 可以走到 或者 ,在不走出棋盘的情况下。二人轮流操作,不允许不操作。问先手是否有必胜、平、败策略。。
解法:设 为走到 的先手情况。先手必胜即是只有走到 A
才有 ,必败是走到 B
才算 ,平局则不能碰到任何一个非 .
的格子,只有 。利用 的奇偶性判断先后手,先手取 转移,后手取 转移。注意清空数组。
#include <bits/stdc++.h>
using namespace std;
const int N = 500;
int f[N + 5][N + 5];
char a[N + 5][N + 5];
int main()
{
int t, n, m;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n;i++)
scanf("%s", a[i] + 1);
memset(f, 0, sizeof(f));
for (int i = n; i >= 1;i--)
for (int j = m; j >= 1;j--)
{
if (a[i][j] == 'A')
f[i][j] = 1;
else if (a[i][j] == 'B' || (i == n && j == m))
continue;
else if (i == n)
f[i][j] = f[i][j + 1];
else if (j == m)
f[i][j] = f[i + 1][j];
else
{
if ((i + j) % 2 == 0)
f[i][j] = max(f[i + 1][j], f[i][j + 1]);
else
f[i][j] = min(f[i + 1][j], f[i][j + 1]);
}
}
if(f[1][1])
printf("yes ");
else
printf("no ");
memset(f, 0, sizeof(f));
for (int i = n; i >= 1;i--)
for (int j = m; j >= 1;j--)
{
if (a[i][j] != '.')
f[i][j] = 1;
else if (i == n && j == m)
f[i][j] = 0;
else if (i == n)
f[i][j] = f[i][j + 1];
else if (j == m)
f[i][j] = f[i + 1][j];
else
{
if ((i + j) % 2 == 0)
f[i][j] = min(f[i + 1][j], f[i][j + 1]);
else
f[i][j] = max(f[i + 1][j], f[i][j + 1]);
}
}
if(!f[1][1])
printf("yes ");
else
printf("no ");
memset(f, 0, sizeof(f));
for (int i = n; i >= 1;i--)
for (int j = m; j >= 1;j--)
{
if (a[i][j] == 'B')
f[i][j] = 1;
else if (a[i][j] == 'A' || (i == n && j == m))
continue;
else if (i == n)
f[i][j] = f[i][j + 1];
else if (j == m)
f[i][j] = f[i + 1][j];
else
{
if ((i + j) % 2 == 0)
f[i][j] = max(f[i + 1][j], f[i][j + 1]);
else
f[i][j] = min(f[i + 1][j], f[i][j + 1]);
}
}
if(f[1][1])
printf("yes\n");
else
printf("no\n");
}
return 0;
}