[TC11326]ImpossibleGame

题目大意:

一类字符串仅由'A','B','C','D'四种字母组成。对于这样的一个字符串\(S\),可以用以下两种方式之一修改这个字符串:

  1. 交换\(S\)中的相邻两个字母;
  2. 使用一种魔法。魔法共\(m(m\le50)\)种,其中第\(i\)种可以将\(S\)中一个等于\(X_i\)的子串替换为\(y_i\),保证\(|X_i|=|Y_i|\)。

求对于所有这样的长度为\(n(n\le30)\)的字符串\(S\),修改过程中出现的不同的字符串最多能有多少?

思路:

对于第一种操作,显然若两个字符串中各字符出现次数对应相等,则这两个字符串之间可以相互转化。

因此我们可以用一个三元组\((a,b,c)\)表示字符串的状态,其中\(a,b,c\)分别表示字符'A','B','C'出现的次数。

魔法就相当于在这些状态间连边。

缩点后在DAG上DP即可。

时间复杂度\(\mathcal O(n^3m)\)

源代码:

#include<stack>
#include<queue>
#include<string>
#include<vector>
class ImpossibleGame {
private:
using int64=long long;
static constexpr int N=31,S=5457;
int64 fac[N],w[S],f[S];
int id[N][N][N],tot,a[S],b[S],c[S],d[S];
void init(const int &n) {
for(register int i=fac[0]=1;i<=n;i++) {
fac[i]=fac[i-1]*i;
}
for(register int i=0;i<=n;i++) {
for(register int j=0;i+j<=n;j++) {
for(register int k=0;i+j+k<=n;k++) {
const int l=n-i-j-k;
id[i][j][k]=++tot;
a[tot]=i;
b[tot]=j;
c[tot]=k;
d[tot]=l;
w[tot]=fac[n]/fac[i]/fac[j]/fac[k]/fac[l];
}
}
}
}
struct Edge {
int u,v;
};
std::vector<Edge> edge;
std::vector<int> e[S];
inline void add_edge(const int &u,const int &v) {
e[u].emplace_back(v);
}
bool ins[S];
std::stack<int> s;
int dfn[S],low[S],scc[S],ind[S];
void tarjan(const int &x) {
dfn[x]=low[x]=++dfn[0];
s.push(x);
ins[x]=true;
for(auto &y:e[x]) {
if(!dfn[y]) {
tarjan(y);
low[x]=std::min(low[x],low[y]);
} else if(ins[y]) {
low[x]=std::min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x]) {
int y;
scc[0]++;
do {
y=s.top();
s.pop();
ins[y]=false;
scc[y]=scc[0];
f[scc[0]]+=w[y];
} while(y!=x);
}
}
std::queue<int> q;
int64 dis[S];
int64 kahn() {
for(register int i=1;i<=scc[0];i++) {
if(!ind[i]) {
dis[i]=f[i];
q.push(i);
}
}
int64 ret=0;
while(!q.empty()) {
const int x=q.front();
q.pop();
for(auto &y:e[x]) {
dis[y]=std::max(dis[y],dis[x]+f[y]);
if(!--ind[y]) {
q.push(y);
}
}
ret=std::max(ret,dis[x]);
}
return ret;
}
public:
int64 getMinimum(const int &n,const std::vector<std::string> &s,const std::vector<std::string> &t) {
init(n);
const int m=s.size();
for(register int i=0;i<m;i++) {
int w=0,x=0,y=0,z=0,o=0,p=0,q=0,r=0;
const int l=s[i].length();
for(register int j=0;j<l;j++) {
if(s[i][j]=='A') w++;
if(s[i][j]=='B') x++;
if(s[i][j]=='C') y++;
if(s[i][j]=='D') z++;
if(t[i][j]=='A') o++;
if(t[i][j]=='B') p++;
if(t[i][j]=='C') q++;
if(t[i][j]=='D') r++;
}
for(register int i=1;i<=tot;i++) {
if(a[i]<w||b[i]<x||c[i]<y||d[i]<z) continue;
const int &j=id[a[i]-w+o][b[i]-x+p][c[i]-y+q];
if(i==j) continue;
add_edge(i,j);
edge.emplace_back((Edge){i,j});
}
}
for(register int i=1;i<=tot;i++) {
if(!dfn[i]) tarjan(i);
}
for(register int i=1;i<=tot;i++) {
e[i].clear();
}
for(auto &e:edge) {
const int &u=e.u,&v=e.v;
if(scc[u]!=scc[v]) {
add_edge(scc[u],scc[v]);
ind[scc[v]]++;
}
}
return kahn();
}
};

[TC11326]ImpossibleGame的更多相关文章

  1. NOI.AC NOIP模拟赛 第二场 补记

    NOI.AC NOIP模拟赛 第二场 补记 palindrome 题目大意: 同[CEOI2017]Palindromic Partitions string 同[TC11326]Impossible ...

随机推荐

  1. Dubbo学习笔记9:Dubbo服务提供方启动流程源码分析

    首先我们通过一个时序图,直观看下Dubbo服务提供方启动的流程: 在<Dubbo整体框架分析>一文中我们提到,服务提供方需要使用ServiceConfig API发布服务,具体是调用代码( ...

  2. 【LibreOJ】#6392. 「THUPC2018」密码学第三次小作业 / Rsa 扩展欧几里得算法

    [题目]#6392. 「THUPC2018」密码学第三次小作业 / Rsa [题意]T次询问,给定正整数c1,c2,e1,e2,N,求正整数m满足: \(c_1=m^{e_1} \ \ mod \ \ ...

  3. SDWebImage源码阅读-第二篇

    一  SDWebImageManager的downloadImageWithURL的方法 上一篇,我们刚开了个头,分析了一下开始加载图片之前如何取消其他正在下载的任务,接着,我们回到 - (void) ...

  4. python中的__iter__ __reversed__ __next__

    __reversed__ 返回集合的倒叙迭代器,如果没有实现这个方法,reversed()会去使用__getitem__和__len__来实现 介绍__next__和 __iter__方法需要了解下可 ...

  5. 产品排序(2015 年北大自招夏令营) (与栈相关的区间DP)

    题面: \(solution:\) 又是一道\(DP\)的好题啊!状态并不明显,需要仔细分析,而且还结合了栈的特性! 做这一类题,只要出题人有点理想,一定会在栈的性质上做点文章,所以我们尽量围绕栈的性 ...

  6. Linux中普通用户提权为超级用户

    首先创建一个普通用户,并且给普通用户设置一个密码,保证能用su 命令能用普通用户登录 [root@ahu ~]# useradd test [root@ahu ~]# passwd test New ...

  7. python3迭代器和生成器

    1.手动访问迭代器中的元素 #要手动访问迭代器中的元素,可以使用next()函数 In [3]: with open('/etc/passwd') as f: ...: try: ...: while ...

  8. RPM Database

    RPM Database RPM 不仅在安装.升级.卸载方面工作出色,而且在查询和验证方面也表现非凡.你很久前安装了一个数据库软件,但现在忘记了它的版本号,也不知道它的说明文档的位置,可以通过 RPM ...

  9. 【题解】BZOJ 1901: Zju2112 Dynamic Rankings

    题目传送门(权限题) 一道类似的非权限题 题意 N个数的序列,每次修改一个数或者询问区间里的第K小.可以离线. 简要做法 假如要求在线,可以树状数组套个线段树~ 但是这题是可以离线的,就可以乱搞整体二 ...

  10. 002_tmux详解

    参考下赖老师的: http://mingxinglai.com/cn/2012/09/tmux/ 一. 二. http://wdxtub.com/2016/03/30/tmux-guide/   (待 ...