5.18 题解
一篇题解需要一个头图。
A
状压 BFS。
考虑状压下标 x = i >> 2, y = i & 3
,而 i == x << 2 | y
。
剩下的就好写了。
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
int s, t, d[100050], f[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};queue<int> q;
int main()
{
memset(d, -1, sizeof d);
for(int i = 0, x;i < 16;++i) scanf("%1d", &x), s |= x << i;
for(int i = 0, x;i < 16;++i) scanf("%1d", &x), t |= x << i;
d[s] = 0;q.push(s);while(!q.empty())
{
int u = q.front();q.pop();
if(u == t) {printf("%d", d[u]);break;}
for(int i = 0, x, y;i < 16;++i) if(u & 1 << i)
for(int j = 0, x = i >> 2, y = i & 3, a, b, k, v;j < 4;++j)
{
a = x + f[j][0];b = y + f[j][1];
if(a >= 0 && a < 4 && b >= 0 && b < 4 && !(u & 1 << (k = a << 2 | b))
&& !~d[v = u & ~(1 << i) | 1 << k]) d[v] = d[u] + 1, q.push(v);
}
}
return 0;
}
B
啊这题我做过啊,不对我怎么 40pts。
Sol 1
直接用一个数据结构维护这个牌堆,发现需要区间平移和单点删除,FHQ 维护之。
#include <cstdio>
#include <cstdlib>
inline int R()
{
int q = 0;char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') q = q * 10 + c - '0', c = getchar();
return q;
}
void P(int x) {if(x >= 10) P(x / 10);putchar(x % 10 + '0');}
struct T
{
T *l, *r;int v, k, s;
T(int _) : l(0), r(0), v(_), k(rand()), s(1) {}
void u() {s = 1;if(l) s += l->s;if(r) s += r->s;}
}*r, *a, *b, *c;
void S(T *x, int k, T *&a, T *&b)
{
if(!x) {a = b = 0;return;}int z = x->l ? x->l->s : 0;
if(z >= k) b = x, S(x->l, k, a, b->l), b->u();
else a = x, S(x->r, k - z - 1, a->r, b), a->u();
}
T *M(T *a, T *b)
{
if(!a) return b;if(!b) return a;
if(a->k < b->k) {a->r = M(a->r, b);a->u();return a;}
else {b->l = M(a, b->l);b->u();return b;}
}
int n, x;
int main()
{
srand(388651);
n = R();for(int i = 1;i <= n;++i) r = M(r, new T(i));while(n--)
x = R() % r->s, S(r, x, a, c), S(c, 1, b, c), P(b->v), puts(""), r = M(c, a);
return 0;
}
洛谷上 AC 了,然后因为神秘原因被卡常了。
Sol 2
维护
若当前指针在
树状数组维护
#include <cstdio>
#include <algorithm>
using namespace std;
int n, p, c[700050];
void M(int x) {for(;x <= n;x += x & -x) --c[x];}
int Q(int x, int y)
{
int q = 0;for(--x;y > x;y &= y - 1) q += c[y];
for(;x > y;x &= x - 1) q -= c[x];return q;
}
int K(int k)
{
int q = 0, s = 0;for(int i = __lg(n), x, y;i >= 0;--i)
if((x = q | 1 << i) <= n && (y = s + c[x]) < k) q = x, s = y;
return q + 1;
}
int main()
{
scanf("%d", &n);for(int i = 1;i <= n;++i) c[i] = i & -i;
for(int i = 0, r, z;i < n;++i)
{
scanf("%d", &r);r = r % (n - i) + 1;
if((z = Q(1, p) + r) <= n - i) M(p = K(z)), printf("%d\n", p);
else M(p = K(r - Q(p, n))), printf("%d\n", p);
}
return 0;
}
啥卡常没加直接到最优解 rk3 了,树状数组上倍增这么小众的吗
C
发现如果没有不能往回走的限制就是一个裸倍增 Floyd,所以考虑怎么把这个限制去掉。
考虑点边互换,
特别地,为了满足不能往回走的限制,原图上
则新图上一条长度为
在新图上建
#include <cstdio>
#include <cstring>
#define M 45989
int n, m, k, s, t, c, u[160], v[160];
struct S
{
int a[160][160];
S() {memset(a, 0, sizeof a);}
S operator*(S b)
{
S q;
for(int i = 1;i <= c;++i)
for(int j = 1;j <= c;++j)
for(int k = 1;k <= c;++k)
q.a[i][j] = (q.a[i][j] + a[i][k] * b.a[k][j]) % M;
return q;
}
}b, q;
int main()
{
scanf("%d%d%d%d%d", &n, &m, &k, &s, &t);
u[++c] = n;v[c] = s;
for(int i = 0, x, y;i < m;++i)
scanf("%d%d", &x, &y), u[++c] = x, v[c] = y, u[++c] = y, v[c] = x;
u[++c] = t;v[c] = n + 1;++k;
for(int i = 1;i <= c;++i)
for(int j = 1;j <= c;++j)
if(i != j && i != (j ^ 1) && v[i] == u[j])
b.a[i][j] = 1;
for(int i = 1;i <= c;++i) q.a[i][i] = 1;
for(;k;k >>= 1, b = b * b)
if(k & 1) q = q * b;
printf("%d", q.a[1][c]);
return 0;
}
D
树上 DP。设
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具