A-Array
题目大意:
给出一个序列a1、a2 … an ,a的倒数和小于等于1/2,构造一个序列(首位相连),使得相邻的i之间不超过ai。
思路:
只要a的倒数和小于1,就可以保证这个序列的存在的。因此将每个a取小于a的最大的2的次幂,可以保证改变后的a的倒数和小于1,然后将a排序,从小到达往序列中放数即可,当放置的位置有数字时就向后移动到空位置,因此都是2的次幂,因此一旦找到空位置后,之后每隔ai的位置都是空的,这也是将a取成2的次幂的原因。可以说这是一道非常巧妙的题。
AC代码:
#include <bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
using namespace std;
const long long mod = 1e9 + 7;
long long ksm(long long base, long long power)
{
long long result = 1;
base %= mod;
while (power)
{
if (power & 1)
result = (result * base) % mod;
power >>= 1;
base = (base * base) % mod;
}
return result;
}
long long dp[14][150];
long long dfs(int s, int r)
{
if (dp[s][r] != 0) return dp[s][r];
if (s == r)
dp[s][r] = (s + 1) / 2;
else if (s == 1)
dp[1][r] = (1 + (r - 3) * ksm(r, mod - 2) % mod * dfs(s, r - 1) % mod) % mod;
else
dp[s][r] = (1 + 3 * s * ksm(r, mod - 2) % mod * dfs(s - 2, r - 1) % mod + (r - 3 * s) * ksm(r, mod - 2) % mod * dfs(s, r - 1) % mod) % mod;
return dp[s][r];
}
signed main()
{
mem(dp, 0);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t, cnt;
char str[50];
map<int, int> m;
cin >> t;
for (int i = 1; i <= t; i++)
{
m.clear();
cnt = 0;
cin >> str;
for (int j = 0; j < 26; j += 2)
m[str[j] * 137 + str[j + 1]]++;
for (auto it : m)
if (it.second == 1) cnt++;
cout << "Case #" << i << ": " << dfs(cnt, 123) << "\n";
}
return 0;
}
B-Eezie and Pie
题目大意:
有一棵树,每个结点向上能达到的距离为di , 对于每个点,求出能到达该点的点数。
思路:
类似前缀和的做法,初始时每个点的值为1,得到每个点不能到达的最近祖先,将其值减1。从下往上算出每个点的值,计算方法为该点自身的值加上所有子树的值。
找最大祖先如果用倍增的话,复杂度为O(nlogn),可能会被卡常数,另一种方法是在dfs时用一个数组来记录路径上的点,从而用O(n)的方法找到每个点的最大祖先。
AC代码:
#include <bits/stdc++.h>
const int N = 2e6 + 5;
using namespace std;
vector<int> g[N];
int path[N], d[N], ans[N], n, cnt = 0;
void dfs(int u, int f)
{
path[++cnt] = u; //将当前的点加入路径中
if (d[u] + 1 < cnt) //不能到达的最近祖先减1
ans[path[cnt - d[u] - 1]]--;
for (auto v : g[u])
{
if (v == f) continue;
dfs(v, u);
}
for (auto v : g[u])
{
if (v == f) continue;
ans[u] += ans[v];
}
cnt--; // dfs结束,将该点弹出
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int u, v;
cin >> n;
for (int i = 1; i <= n; i++)
ans[i] = 1;
for (int i = 2; i <= n; i++)
{
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; i++)
cin >> d[i];
dfs(1, 0);
for (int i = 1; i <= n; i++)
cout << ans[i] << ' ';
return 0;
}
M-Z-Game on grid
题目大意:
在一个矩形棋盘上,每个位置可能为’A’、‘B’、'.‘其中之一,Alice和Bob轮流移动棋子,每次只能向右或向下移动棋子,当棋子移动到’A’上时Alice获胜,当棋子移动到’B’上时Bob获胜,当棋子不能被移动且位于’.'上时,平局。棋子初始位置在左上角,Alice先手,Bob走的每一步都是随机的,问Alice能否控制自己获胜、平局或是输掉。
思路:
可以把两人移动棋子的情况画成一棵树,以Alice获胜为例,那么无论Bob怎么走,棋子总是位于获胜的路径上。
当Alice移动时,子树中至少要有一棵位于获胜的路径上才行,当Bob移动时,所有的子树都必须位于获胜的路径上。
AC代码:
#include <bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
const int N = 5e2 + 5;
using namespace std;
char g[N][N];
int n, m;
int sg[2][N][N]; // sg[0][i][j]表示棋子位于(i,j)上且是Alice移动的结果
// Alice赢,p为0表示为Alice在走,1表示Bob走
bool dfs1(int p, int i, int j)
{
if (sg[p][i][j] != -1) return sg[p][i][j]; //已经有结果了,直接返回
if (g[i][j] == 'A') return 1; //赢了
if (g[i][j] == 'B') return 0; //输了
if (i == n && j == m) return 0; //平局
bool res;
if (p == 0) // Alice走,有一条路径为获胜路径就行
{
res = 0;
if (i + 1 <= n) res |= dfs1(p ^ 1, i + 1, j);
if (j + 1 <= m) res |= dfs1(p ^ 1, i, j + 1);
sg[p][i][j] = res;
}
else // Bob走,所有的路径为获胜路径才行
{
res = 1;
if (i + 1 <= n) res &= dfs1(p ^ 1, i + 1, j);
if (j + 1 <= m) res &= dfs1(p ^ 1, i, j + 1);
sg[p][i][j] = res;
}
return sg[p][i][j];
}
//平局
bool dfs2(int p, int i, int j)
{
if (sg[p][i][j] != -1) return sg[p][i][j];
if (g[i][j] != '.')
return 0;
if (i == n && j == m && g[i][j] == '.') return 1;
bool res;
if (p == 0)
{
res = 0;
if (i + 1 <= n) res |= dfs2(p ^ 1, i + 1, j);
if (j + 1 <= m) res |= dfs2(p ^ 1, i, j + 1);
sg[p][i][j] = res;
}
else
{
res = 1;
if (i + 1 <= n) res &= dfs2(p ^ 1, i + 1, j);
if (j + 1 <= m) res &= dfs2(p ^ 1, i, j + 1);
sg[p][i][j] = res;
}
return sg[p][i][j];
}
// Bob赢
bool dfs3(int p, int i, int j)
{
if (sg[p][i][j] != -1) return sg[p][i][j];
if (g[i][j] == 'B') return 1;
if (g[i][j] == 'A') return 0;
if (i == n && j == m) return 0;
bool res;
if (p == 0) // A走
{
res = 0;
if (i + 1 <= n) res |= dfs3(p ^ 1, i + 1, j);
if (j + 1 <= m) res |= dfs3(p ^ 1, i, j + 1);
sg[p][i][j] = res;
}
else
{
res = 1;
if (i + 1 <= n) res &= dfs3(p ^ 1, i + 1, j);
if (j + 1 <= m) res &= dfs3(p ^ 1, i, j + 1);
sg[p][i][j] = res;
}
return sg[p][i][j];
}
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> g[i] + 1;
mem(sg, -1);
if (dfs1(0, 1, 1))
cout << "yes ";
else
cout << "no ";
mem(sg, -1);
if (dfs2(0, 1, 1))
cout << "yes ";
else
cout << "no ";
mem(sg, -1);
if (dfs3(0, 1, 1))
cout << "yes\n";
else
cout << "no\n";
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--)
solve();
return 0;
}