【YBT2022寒假Day7 A】字符变换(状压)(Tarjan)(DP)

字符变换

题目链接:YBT2022寒假Day7 A

题目大意

给你一个只包含四种字符的字符串,和一些二元组 (x,y),x,y 为两个等长的字符串。
一个二元组的作用是可以选择字符串中一个与 x 相同的子串把它变成 y。
你也可以任意交换字符串两个位置的字符。
然后问你从任意字符串开始进行任意次变换,最多能得到多少个字符串。

思路

你考虑因为可以交换位置,所以字符串我们只需要关心它每个字符的个数,至于这个的方案你就可以用 n!a!b!c!(nabc)! 来求。
然后要注意的是因为 n 有三十,不能直接预处理阶乘,我们就分解质因数之类的搞即可。

然后你发现如果通过变换某个状态 x 可以变到某个状态 y,那我们可以把它们连一条有向边,代表如果你变换到 x,你可以继续变换到 y
然后你可以用 Tarjan 缩点,然后我们考虑这个状态的数量。

然后发现字符串长度很小,我们考虑状压,发现状态数不多可以搞,设 fx 为从任意点开始走到 x 的最大数量。
(压三个数的即可,第四个直接用 n 减去前三个就是了)

然后这么搞 Tarjan 完 DP 一下就得到答案了。

代码

#include<queue> #include<cstdio> #include<vector> #include<cstring> #include<iostream> #define ll long long #define MAXN ((n + 1) * (n + 1) * (n + 1)) using namespace std; struct awa { int a[4]; }; struct node { int to, nxt; }e[6000001], e_[6000001]; int n, m, le[1000001], KK, a[1001][5], b[1001][5], sz[1001]; int le_[1000001], KK_; char s[31], ss[31]; ll val[1000001]; vector <int> q; int get_(int a, int b, int c, int d) { return a * (n + 1) * (n + 1) + b * (n + 1) + c; } ll clac(awa now) { q.clear(); for (int i = 0; i < 4; i++) { for (int j = 2; j <= now.a[i]; j++) q.push_back(j); } // __int128 re = 1; ll re = 1; for (int i = 2; i <= n; i++) { re *= i; for (int j = 0; j < q.size(); j++) if (q[j] != 1 && re % q[j] == 0) { re /= q[j]; q[j] = 1; } } return (ll)re; } int dfn[1000001], low[1000001], col[1000001], tmpt, sta[1000001], tot; ll vals[1000001]; void add(int x, int y) { e[++KK] = (node){y, le[x]}; le[x] = KK; } void add_(int x, int y) { e_[++KK_] = (node){y, le_[x]}; le_[x] = KK_; } void tarjan(int now) { dfn[now] = low[now] = ++tmpt; sta[++sta[0]] = now; for (int i = le[now]; i; i = e[i].nxt) if (!dfn[e[i].to]) { tarjan(e[i].to); low[now] = min(low[now], low[e[i].to]); } else if (!col[e[i].to]) low[now] = min(low[now], low[e[i].to]); if (dfn[now] == low[now]) { col[now] = ++tot; vals[tot] = val[now]; while (sta[sta[0]] != now) { vals[tot] += val[sta[sta[0]]]; col[sta[sta[0]]] = tot; sta[0]--; } sta[0]--; } } queue <int> qq; ll f[1000001], ans; int du[1000001]; int main() { // freopen("character.in", "r", stdin); // freopen("character.out", "w", stdout); scanf("%d %d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%s %s", s + 1, ss + 1); sz[i] = strlen(s + 1); for (int j = 1; j <= sz[i]; j++) a[i][s[j] - 'A']++, b[i][ss[j] - 'A']++; } for (int i = 0; i < MAXN; i++) { awa now; now.a[0] = i / (n + 1) / (n + 1) % (n + 1); now.a[1] = i / (n + 1) % (n + 1); now.a[2] = i % (n + 1); if (now.a[0] + now.a[1] + now.a[2] > n) continue; now.a[3] = n - now.a[0] - now.a[1] - now.a[2]; val[i] = clac(now); for (int j = 1; j <= m; j++) { bool yes = 1; for (int k = 0; k < 4; k++) if (now.a[k] < a[j][k]) { yes = 0; break; } if (yes) { int to = get_(now.a[0] - a[j][0] + b[j][0], now.a[1] - a[j][1] + b[j][1], now.a[2] - a[j][2] + b[j][2], now.a[3] - a[j][3] + b[j][3]); if (i != to) add(i, to); } } } for (int i = 0; i < MAXN; i++) { awa now; now.a[0] = i / (n + 1) / (n + 1) % (n + 1); now.a[1] = i / (n + 1) % (n + 1); now.a[2] = i % (n + 1); if (now.a[0] + now.a[1] + now.a[2] > n) continue; now.a[3] = n - now.a[0] - now.a[1] - now.a[2]; if (!dfn[i]) tarjan(i); } for (int i = 0; i < MAXN; i++) { awa now; now.a[0] = i / (n + 1) / (n + 1) % (n + 1); now.a[1] = i / (n + 1) % (n + 1); now.a[2] = i % (n + 1); if (now.a[0] + now.a[1] + now.a[2] > n) continue; now.a[3] = n - now.a[0] - now.a[1] - now.a[2]; for (int j = 1; j <= m; j++) { bool yes = 1; for (int k = 0; k < 4; k++) if (now.a[k] < a[j][k]) { yes = 0; break; } if (yes) { int to = get_(now.a[0] - a[j][0] + b[j][0], now.a[1] - a[j][1] + b[j][1], now.a[2] - a[j][2] + b[j][2], now.a[3] - a[j][3] + b[j][3]); if (col[i] != col[to]) add_(col[i], col[to]), du[col[to]]++; } } } for (int i = 1; i <= tot; i++) if (!du[i]) { qq.push(i); f[i] = vals[i]; ans = max(ans, f[i]); } while (!qq.empty()) { int now = qq.front(); qq.pop(); for (int i = le_[now]; i; i = e_[i].nxt) { int x = e_[i].to; f[x] = max(f[x], f[now]); du[x]--; if (!du[x]) { qq.push(x); f[x] += vals[x]; ans = max(ans, f[x]); } } } printf("%lld", ans); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT2022Day7_A.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示