# 鸽子要跑路
# 题目描述
鸽子位于平面直角坐标系上的整点 ,每次可以朝上下左右四个方向选一个走一个单位长度,走的时候需要保证横纵坐标非负,目的地是 。
鸽子的初始疲劳值为 ,如果当前位置 满足 x&y > 0
,那么疲劳值加 ,否则不变。起点与终点的疲劳值不计入答案。
一共 组数据,对于每组数据求从 到 的最小疲劳值。。
# 解题思路
是一道找规律题,先打一手表:
发现是个 谢尔宾斯基三角形。
答案有两种情况,一种是直接走,每一步都算入疲劳值;另一种是先走到一个 上,再找个最近的位置走到目标点 (所有的 都是联通的)
对于一个正方形的左上部分,是一种递归结构,可递归求解。当落入某个正方形的右下时,计算与边界的距离。
# Code
#define Aniciry Meteorshower_Y | |
#include<algorithm> | |
#include<iostream> | |
#include<cstdio> | |
#include<cmath> | |
using namespace std; | |
typedef long long ll; | |
auto _find(ll x, ll y, ll len) -> ll; | |
int T; ll a, b, c, d; | |
inline auto work() -> void; | |
signed main() | |
{ | |
scanf("%d", &T); | |
while (T--) work(); | |
return 0; | |
} | |
inline auto work() -> void | |
{ | |
ll part1, part2, len; | |
scanf("%lld%lld", &a, &b); | |
scanf("%lld%lld", &c, &d); | |
ll ans = abs(a-c)+abs(b-d); | |
if(a != c or b != d) ans -= 1; | |
len = 1; | |
while(len <= max(a, b)) len <<= 1; | |
part1 = _find(a, b, len); | |
len = 1; | |
while(len <= max(c, d)) len <<= 1; | |
part2 = _find(c, d, len); | |
ans = min(ans, part1+part2); | |
printf("%lld\n", ans); | |
} | |
inline auto _find(ll x, ll y, ll len) -> ll | |
{ | |
if(x+y >= len) return min({len-x-1, len-y-1, x+y-len}); | |
len >>= 1; | |
if(x == len or y == len) return 0; | |
if(x > len) x -= len; | |
if(y > len) y -= len; | |
return _find(x, y, len); | |
} |
# abab
# 题目描述
给一个只包含 a
和 b
的字符串,问最多有多少不相交的子序列 abab
。
共 组数据,每组数据包含一个字符串 。
# 解题思路
abab
可以拆成两个 ab
, 所以问题就转化为了找出尽量多的不相交的 ab
。
记字符串中, ab
相互交错的数量最多的为 ,一共能找到 对 ab
。
- 当 时,会剩下相互交错的不能匹配的
ab
,答案为 ; - 当 时,所有的
ab
一定能找到一种方案全部匹配,答案为
# Code
#define Aniciry Meteorshower_Y | |
#include<iostream> | |
#include<cstring> | |
#include<cstdio> | |
#include<stack> | |
using namespace std; | |
namespace Aniciry | |
{ | |
const int READSIZE = 100000; | |
char ibuf[READSIZE], *p1, *p2, ch; | |
#define isseen(ch) (ch > 32) | |
#define isspace(ch) (ch <= 32 and ch != EOF) | |
#define isdigit(ch) (ch >= '0' and ch <= '9') | |
#define getchar() ((p1==p2)and(p2=(p1=ibuf)+fread(ibuf,1,READSIZE,stdin),p1==p2)?(EOF):(*p1++)) | |
template <class T> | |
inline auto read(T &x) -> void | |
{ | |
x = 0; ch = getchar(); | |
while(!isdigit(ch) and ch != EOF) ch = getchar(); | |
if(ch == EOF) return void(); | |
while(isdigit(ch)) x = x*10+(ch-'0'), ch = getchar(); | |
} | |
inline auto read(char &x) -> void | |
{ | |
x = getchar(); | |
while(isspace(x)) x = getchar(); | |
} | |
inline auto read(char *s) -> void | |
{ | |
ch = getchar(); | |
while(isspace(ch)) ch = getchar(); | |
while(isseen(ch)) *s = ch, ++s, ch = getchar(); | |
*s = '\000'; | |
} | |
template <typename T, typename ...T1> | |
inline auto read(T &a, T1 &...other) -> void{ | |
return read(a), read(other...); | |
} | |
} | |
using namespace Aniciry; | |
const int N = 1e7+10; | |
int T, n, d[N]; char s[N]; | |
auto work() -> void; | |
int main() | |
{ | |
read(T); | |
while(T--) work(); | |
return 0; | |
} | |
auto work() -> void | |
{ | |
stack<int> st; int mx = 0, cnt = 0; | |
read(s+1); n = strlen(s+1); | |
for(int i = 1; i <= n; i += 1) | |
{ | |
d[i] = 0; | |
if(s[i] == 'a') st.push(i); | |
else if(!st.empty()) d[st.top()] += 1, st.pop(), d[i] -= 1, cnt += 1; | |
} | |
for(int i = 1, now = 0; i <= n; i += 1) | |
if(now += d[i], now > mx) mx = now; | |
printf("%d\n", min(cnt/2, cnt-mx)); | |
} |
# 二叉树比大小
# 题目描述
用 代表空树,如果一个节点没有左子树,那么就认为它的左子树是空树(右子树同理)。对于任意二叉树 , 成立;对于任意非空二叉树 , 不成立。
用 代表左子树, 代表右子树,对于所有非空二叉树 ,, 当且仅当 且 ; 当且仅当 且 ,否则 。
给定节点编号为 的二叉树 。 的初始形态为 。对 重复进行以下操作:任选 中的一个儿子数量不超过 的节点,为这个节点增加一个儿子(使得 仍然是二叉树)。左右有区别。
问有多少不同的 满足 的节点数为 且 。
# 解题思路
如果 ,那么 的每一个子树 和它对应的 ,都有大小关系的限制。这个限制要么是 ,要么是 。我们可以在要求 的子树的根节点上标记状态 ,在要求 的子树的根节点上标记状态 。左儿子的状态和父节点相同,右儿子的状态和父节点相反。
我可以且只可以在状态为 的地方添加节点。可以用一次 dfs 找到所有可以添加新节点的位置。我们只关心这些位置的数量,设为 。
问题转化成这样:
有 个互相独立的位置,放上 个节点,问最终形成的二叉树森林有几种。
记 为上述问题的答案。
分类讨论第 个位置上是否挂了新的节点,如果挂了一个节点,那么还需要的节点数少了 ,一共需要挂的位置多了 ;如果不挂这个节点,后面就不考虑他了,一共要挂的位置就少了 。
所以转移方程为 。
把他看成在二维平面上的行走问题,则每次可以从 走到 和 (需要保证 ),问题是从 走到
然后把坐标转化一下,将 转化为 , 那么从 往后走一步走到的点就是 和 ,同时上面的限制就变成了要保证 ,而问题是从 走到 。总方案是 ,枚举每第一次超出限制的点,就和 No.3 Count 那道题一样,得到最后的答案为 .
# Code
#define Aniciry Meteorshower_Y | |
#include<iostream> | |
#include<cstdio> | |
using namespace std; | |
typedef long long ll; | |
const int N = 1e6+10; | |
const int mod = 1914270647; | |
namespace Aniciry | |
{ | |
const int READSIZE = 100000; | |
char ibuf[READSIZE], *p1, *p2, ch; | |
#define isseen(ch) (ch > 32) | |
#define isspace(ch) (ch <= 32 and ch != EOF) | |
#define isdigit(ch) (ch >= '0' and ch <= '9') | |
#define getchar() ((p1==p2)and(p2=(p1=ibuf)+fread(ibuf,1,READSIZE,stdin),p1==p2)?(EOF):(*p1++)) | |
template <class T> | |
inline auto read(T &x) -> void | |
{ | |
x = 0; ch = getchar(); | |
while(!isdigit(ch) and ch != EOF) ch = getchar(); | |
if(ch == EOF) return void(); | |
while(isdigit(ch)) x = x*10+(ch-'0'), ch = getchar(); | |
} | |
inline auto read(char &x) -> void | |
{ | |
x = getchar(); | |
while(isspace(x)) x = getchar(); | |
} | |
inline auto read(char *s) -> void | |
{ | |
ch = getchar(); | |
while(isspace(ch)) ch = getchar(); | |
while(isseen(ch)) *s = ch, ++s, ch = getchar(); | |
*s = '\000'; | |
} | |
template <typename T, typename ...T1> | |
inline auto read(T &a, T1 &...other) -> void{ | |
return read(a), read(other...); | |
} | |
} | |
using namespace Aniciry; | |
int n, m, cnt; | |
int ls[N], rs[N], vis[N]; | |
ll fact[N*3], finv[N*3], ans; | |
__int128_t base = ((__int128_t)1<<64)/mod; | |
inline auto C(int n, int m) -> ll; | |
inline auto ksm(ll a, int b) -> ll; | |
inline auto prework(int n) -> void; | |
inline auto dfs(int x, int tp) -> void; | |
inline auto modp(const ll x) -> ll{return x-mod*(base*x>>64);} | |
int main() | |
{ | |
read(n, m); prework(3e6); | |
for(int i = 1; i <= n; i += 1) | |
{ | |
read(ls[i], rs[i]); | |
vis[ls[i]] = vis[rs[i]] = 1; | |
} | |
for(int i = 1; i <= n; i += 1) | |
if(!vis[i]) dfs(i, 1); | |
ans = C(cnt+2*m-1, m)-C(cnt+2*m-1, cnt+m); | |
printf("%lld", modp(ans+mod)); | |
return 0; | |
} | |
inline auto dfs(int x, int tp) -> void | |
{ | |
if(!x) return (void)(cnt += tp); | |
dfs(ls[x], tp); | |
dfs(rs[x], tp^1); | |
} | |
inline auto prework(int n) -> void | |
{ | |
fact[0] = finv[0] = 1; | |
for(int i = 1; i <= n; i += 1) | |
fact[i] = modp(fact[i-1]*i); | |
finv[n] = ksm(fact[n], mod-2); | |
for(int i = n-1; i >= 1; i -= 1) | |
finv[i] = modp(finv[i+1]*(i+1)); | |
} | |
inline auto C(int n, int m) -> ll | |
{ | |
if(n < m) return 0; | |
return modp(modp(fact[n]*finv[m])*finv[n-m]); | |
} | |
inline auto ksm(ll a, int b) -> ll | |
{ | |
ll ans = 1; | |
for(; b; a = modp(a*a), b >>= 1) | |
if(b&1) ans = modp(ans*a); | |
return ans; | |
} |