正题

题目链接:https://www.ybtoj.com.cn/contest/115/problem/2


题目大意

给出一个包含字母变量和若干种同级操作符的后缀表达式。求一个等价的表达式满足该表达式的连续相同段最少。

\(1\leq |S|\leq 2500\)


解题思路

构建出表达树先,然后看一下什么能够化简,

  1. 两个相邻的相同运算符可以合并
  2. 一个非叶子节点下的相同叶子节点(字母节点)可以合并

先把这些合并了,然后目前的最优解就是现在的节点数量,但是还有一种情况可以合并。

就是兄弟节点中,非叶子节点和叶子节点可以合并。

用类树形\(dp\)求出所有节点的子树中的所有表达式的最优答案,如果不考虑上面那种情况就有

\[ans_i=1+\sum_{x->y}ans_y
\]

然后考虑一个非叶子节点在最优情况下能否以某个字母作为开头,定义\(avl_{x,c}\)表示\(x\)节点在\(ans\)最大的情况下能否以\(c\)作为开头。(因为上面那种情况最多剩下一个费用,如果这里牺牲了子树的最优性那么至少需要增加一点费用,显然是一定不优的)

那么对于一个节点的所有儿子,将非叶子节点和叶子节点分成二分图,如果非叶子节点的\(x\)满足\(avl_{x,c}=1\),那么向\(c\)连边。

然后跑二分图匹配就是\(ans\)可以减去的价值。

如何求出\(avl\)?如果一个字母\(c\)是\(x\)的儿子那么显然可以作为开头,否则如果有一个字母\(c\)满足\(x\)的一个非叶子儿子\(y\)使得\(avl_{y,c}=1\),并且在二分图上删去\(y\)节点不会影响答案时,此时将该子树作为开头即可。

如何判断删除一个节点后最大匹配不变,如果原图中该点没有匹配显然可以直接删去。如果有匹配,那么将该节点打上禁止标记后从它的匹配点开始求一条增广路,如果有则可以删去。

时间复杂度\(O(n^2)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N=3100;
struct node{
int to,next;
}a[N];
int n,cnt,tot,ls[N],ans[N];
bool del[N],leaf[N],ch[N][27],avl[N][27];
char s[N];stack<int> st;
namespace M{
node a[N*27];bool v[27];
int tot,ls[27],link[N];
void clear(){
for(int i=1;i<=cnt;i++)link[i]=0;
for(int i=1;i<=26;i++)ls[i]=0;
tot=cnt=0;return;
}
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
int find(int x){
if(v[x])return 0;
int p,q;v[x]=1;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
p=link[y];link[y]=x;
if(!p||find(p))return 1;
link[y]=p;
}
return 0;
}
int Match(int x){
memset(v,0,sizeof(v));
return find(x);
}
int Path(int x){
if(!link[x])return 1;
return Match(link[x]);
}
}
bool isabc(char c)
{return (c>='a')&&(c<='z');}
void addl(int x,int y){
if(leaf[y])ch[x][s[y]-'a'+1]=1;
else{
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;
}
return;
}
void Merge(int x,int y){
for(int i=1;i<=26;i++)ch[x][i]|=ch[y][i];
for(int i=ls[y];i;i=a[i].next)
if(!del[a[i].to])addl(x,a[i].to);
del[y]=1;return;
}
void dfs(int x){
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;dfs(y);
if(s[x]==s[y])Merge(x,y);
}
for(int i=1;i<=26;i++)ans[x]+=ch[x][i];
ans[x]++;return;
}
void dp(int x){
for(int i=ls[x];i;i=a[i].next)
if(!del[a[i].to])dp(a[i].to);
M::clear();
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(del[y])continue;
++cnt;ans[x]+=ans[y];
for(int j=1;j<=26;j++)
if(avl[y][j]&&ch[x][j])
M::addl(j,cnt);
}
for(int i=1;i<=26;i++)
if(ch[x][i])ans[x]-=M::Match(i);
for(int i=1;i<=26;i++)avl[x][i]=ch[x][i];
for(int i=ls[x],p=0;i;i=a[i].next){
int y=a[i].to;
if(del[y])continue;p++;
if(M::Path(p)){
for(int j=1;j<=26;j++)
avl[x][j]|=avl[y][j];
}
}
return;
}
int main()
{
freopen("expr.in","r",stdin);
freopen("expr.out","w",stdout);
scanf("%s",s+1);
int l=strlen(s+1);
for(int i=1;i<=l;i++){
++n;
if(isabc(s[i]))leaf[n]=1;
else{
addl(n,st.top());st.pop();
addl(n,st.top());st.pop();
}
st.push(n);
}
dfs(n);
dp(n);
printf("%d\n",ans[n]);
return 0;
}

YbtOJ#573-后缀表达【二分图匹配】的更多相关文章

  1. cogs_14_搭配飞行员_(二分图匹配+最大流,网络流24题#01)

    描述 http://cojs.tk/cogs/problem/problem.php?pid=14 有一些正飞行员和副飞行员,给出每个正飞行员可以和哪些副飞行员一起飞.一架飞机上必须一正一副,求最多多 ...

  2. Cogs 14. [网络流24题] 搭配飞行员(二分图匹配)

    [网络流24题] 搭配飞行员 ★★☆ 输入文件:flyer.in 输出文件:flyer.out 简单对比 时间限制:1 s 内存限制:128 MB [问题描述] 飞行大队有若干个来自各地的驾驶员,专门 ...

  3. UVA 12549 - 二分图匹配

    题意:给定一个Y行X列的网格,网格种有重要位置和障碍物.要求用最少的机器人看守所有重要的位置,每个机器人放在一个格子里,面朝上下左右四个方向之一发出激光直到射到障碍物为止,沿途都是看守范围.机器人不会 ...

  4. POJ 1274 裸二分图匹配

    题意:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶,告诉每头奶牛愿意产奶的牛棚编号,求出最多能分配到的牛栏的数量. 分析:直接二分图匹配: #include<stdio.h> #includ ...

  5. BZOJ1433 ZJOI2009 假期的宿舍 二分图匹配

    1433: [ZJOI2009]假期的宿舍 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2375  Solved: 1005[Submit][Sta ...

  6. HDU1281-棋盘游戏-二分图匹配

    先跑一个二分图匹配,然后一一删去匹配上的边,看能不能达到最大匹配数,不能这条边就是重要边 /*----------------------------------------------------- ...

  7. HDU 1083 网络流之二分图匹配

    http://acm.hdu.edu.cn/showproblem.php?pid=1083 二分图匹配用得很多 这道题只需要简化的二分匹配 #include<iostream> #inc ...

  8. hdu 5727 Necklace dfs+二分图匹配

    Necklace/center> 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5727 Description SJX has 2*N mag ...

  9. BZOJ 1059 & 二分图匹配

    题意: 判断一个黑白染色的棋盘能否通过交换行或列使对角线上都是黑色. SOL: 真是有点醉...这种问题要么很神要么很水...第一眼感觉很水但就是不造怎么做...想了10分钟怎么感觉就是判断个数够不够 ...

随机推荐

  1. docker部署elasticsearch-+-Kibana(6-8)-+-SpringBoot-2-1-6

    elasticsearch快速开始 docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e ...

  2. VMware + LInux + Xshell 连接环境设置

    一.安装好Centos后,打开设置: 网络连接四中模式桥接模式.NAT模式.仅主机和自定义模式: 1).桥接模式:更公司的局域网连接,等于另一台连接进公司的新电脑 2).NAT模式:与虚拟机使用的计算 ...

  3. 深入浅出Mybatis系列(二)---Mybatis入门

    一.Mybatis环境搭建及简单实例 1. 新建web项目, 添加依赖包:mybatis包.数据库驱动包(我使用的是mysql).日志包(我使用的是log4j), 由于我的是maven项目, 那么添加 ...

  4. SpringBoot中自定义错误页面

    错误页面定制(在有模板引擎的情况下): 有模板的支持下: 在templates文件夹下 建立 error文件夹 在error文件夹下 404.html 500.html 4xx.html (名字就叫4 ...

  5. MySQL5.7.24 安装

    官网地址 https://dev.mysql.com/downloads/mysql/ 1. 安装依赖 yum install -y cmake make gcc gcc-c++ libaio ncu ...

  6. 巧用模糊实现视觉的 3D 效果

    本文较短,将介绍巧用模糊实现视觉 3D 效果的技巧. 我们都知道,在正常的视觉效果中,离我们越近的通常我们会看的越清晰,而离我们较远则相对没那么清晰~ 我们可以利用清晰与模糊两种状态来构建视差效果.像 ...

  7. MySQL数据库迁移之data目录

    其实迁移数据库,一般用sql文件就行,把A服务器数据库的表结构和数据等等导出,然后导入到B服务器数据库, 但是这次数据文件过大,大约有40个G,使用命令行导入,效果不是很好,经常在执行过程中报错.卡死 ...

  8. springMVC学习总结(一) --springMVC搭建

    springMVC学习总结(一) --springMVC搭建 搭建项目 1.创建一个web项目,并在项目中的src文件夹下创建一个包com.myl.controller. 2.添加相应jar包 3.在 ...

  9. Jest中Mock网络请求

    Jest中Mock网络请求 最近需要将一个比较老的库修改为TS并进行单元测试,修改为TS还能会一点,单元测试纯粹是现学现卖了,初学Jest框架,觉得在单元测试中比较麻烦的就是测试网络请求,所以记录一下 ...

  10. Linux上使用设置printf显示的颜色

    我们经常看到别的屏幕五颜六色的很是羡慕,看着很炫是吧.其实我们也可以自己做一个简单的修改,是我们的显示结果也呈现出不同的颜色.shell脚本可能设置的比较多,但是我们平常使用C语言却很少设置它的颜色, ...