zoukankan      html  css  js  c++  java
  • [提高组集训2021] 麻将机

    一、题目

    定义字符集为 \(0\sim9,a\sim z,A\sim Z\)\(62\) 种不同的字符,现在给你一个长度为 \(n\) 的字符串。

    \(m\) 次操作,第 \(i\) 个操作表示把所有 \(x_i\) 的字符变成 \(y_i\),请问在要求每个操作至少执行一次的情况下,最终字符种类的最大值是多少?

    \(n\leq 1000,m\leq 62\times 61\)

    二、解法

    我们把字符看成点,操作看成边建图。首先考虑一个基本的 \(\tt observation\):如果一个点操作了它的某一个出边,那么剩下的出边就不需要操作了。你可能觉得这个垃圾转化没什么币用,但是它其实把边的限制转化到了点上,也就是把边覆盖问题转化成了点覆盖问题,我曾经说过你只有尽可能的简化性质,神秘的结论才会赐福于你,其此之谓也。

    然后考虑原图中的一个路径集合 \(L\),定义它合法为经过了需要覆盖的点,定义它的权值为结尾在原串出现过的路径数量,证明最小权值为最小字符损失可以考虑一下两点:

    • 若存在一个合法的 \(L\) 权值为 \(x\),那么可以找到一个存在损失不超过 \(x\) 的方案。
    • 若存在一个造成 \(x\) 损失的方案,可以找到一个权值不超过 \(x\)\(L\)

    因为上面的结论不难感性理解我就不证了,我们来考虑如何求出最优的 \(L\),首先我们对原图强连通缩点。因为它的本质是最小链覆盖所以我们使用网络流 \(+\) 调整法,魔改一下模板建图即可:

    • 左部为需要覆盖的强连通分量,需要覆盖即大小不为 \(1\) 或者出度不为 \(0\),并且在原串中出现过。
    • 右部的一部分为需要覆盖的强连通分量,如果有边就把左部和右部的强连通分量连起来。另一部分为 \(0\) 的单点,也就是你可以把它作为路径的终点,如果能到达就把左部的强连通分量和它连边(在内部的也算能到达)

    \(|A|\) 为左部集合的大小,那么初始损失量就是 \(|A|\),最小损失量是 \(|A|-flow\),那么答案自然可以计算了。

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <stack>
    #include <queue>
    using namespace std;
    const int M = 1005;
    const int inf = 0x3f3f3f3f;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,Ind,cnt,d[M],mp[M],in[M],dfn[M],low[M],col[M];
    int ans,tot,S,T,a[M],b[M],f[M],dis[M],to[M][M];char s[M];
    vector<int> g[M];stack<int> st;
    struct edge
    {
    	int v,c,next;
    }e[M*M];
    void add(int u,int v,int c)
    {
    	e[++tot]=edge{v,c,f[u]},f[u]=tot;
    	e[++tot]=edge{u,0,f[v]},f[v]=tot;
    }
    int bfs()
    {
    	queue<int> q;q.push(S);dis[S]=1;
    	for(int i=1;i<=T;i++) dis[i]=0;
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		if(u==T) return 1;
    		for(int i=f[u];i;i=e[i].next)
    		{
    			int v=e[i].v;
    			if(!dis[v] && e[i].c>0)
    			{
    				dis[v]=dis[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return 0;
    }
    int dfs(int u,int ept)
    {
    	if(u==T) return ept;
    	int tmp=0,flow=0;
    	for(int i=f[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(dis[v]==dis[u]+1 && e[i].c>0)
    		{
    			tmp=dfs(v,min(ept,e[i].c));
    			if(!tmp) continue;
    			ept-=tmp;flow+=tmp;
    			e[i].c-=tmp;e[i^1].c+=tmp;
    			if(!ept) break;
    		}
    	}
    	return flow;
    }
    void tarjan(int u)
    {
    	dfn[u]=low[u]=++Ind;
    	st.push(u);in[u]=1;
    	for(auto v:g[u])
    	{
    		if(!dfn[v])
    		{
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(in[v])
    			low[u]=min(low[u],dfn[v]);
    	}
    	if(dfn[u]==low[u])
    	{
    		int v;cnt++;
    		do{
    			v=st.top();st.pop();
    			b[cnt]|=a[v];
    			col[v]=cnt;in[v]=0;
    		}while(v^u);
    	}
    }
    int main()
    {
    	freopen("machine.in","r",stdin);
    	freopen("machine.out","w",stdout);
    	for(int i='0';i<='9';i++) mp[i]=++m;
    	for(int i='a';i<='z';i++) mp[i]=++m;
    	for(int i='A';i<='Z';i++) mp[i]=++m;
    	scanf("%s",s+1),n=strlen(s+1);k=read();
    	for(int i=1;i<=n;i++) a[mp[s[i]]]=1;
    	for(int i=1;i<=m;i++) ans+=a[i];
    	while(k--)
    	{
    		scanf("%s",s);to[mp[s[0]]][mp[s[1]]]=1;
    		g[mp[s[0]]].push_back(mp[s[1]]);
    	}
    	for(int k=1;k<=m;k++)
    		for(int i=1;i<=m;i++)
    			for(int j=1;j<=m;j++)
    				to[i][k]|=to[i][j]&to[j][k];
    	for(int i=1;i<=m;i++)
    		if(!dfn[i]) tarjan(i);
    	S=0;T=3*m+1;tot=1;
    	for(int i=1;i<=m;i++)
    		for(int j=1;j<=m;j++)
    			if(to[i][j] && b[col[i]] && !a[j])
    				add(col[i],j+2*m,1);
    	for(int u=1;u<=m;u++)
    		for(auto v:g[u]) if(col[u]^col[v])
    			add(col[u],col[v]+m,1),d[col[u]]++;
    	for(int i=1;i<=m;i++) if(b[i] && d[i])
    		ans--,add(S,i,1),add(i+m,T,1);
    	for(int i=1;i<=m;i++) if(!a[i])
    		add(2*m+i,T,1);
    	while(bfs()) ans+=dfs(S,inf);
    	printf("%d\n",ans);
    }
    
  • 相关阅读:
    BZOJ 1040 (ZJOI 2008) 骑士
    BZOJ 1037 (ZJOI 2008) 生日聚会
    ZJOI 2006 物流运输 bzoj1003
    ZJOI 2006 物流运输 bzoj1003
    NOI2001 炮兵阵地 洛谷2704
    NOI2001 炮兵阵地 洛谷2704
    JLOI 2013 卡牌游戏 bzoj3191
    JLOI 2013 卡牌游戏 bzoj3191
    Noip 2012 day2t1 同余方程
    bzoj 1191 [HNOI2006]超级英雄Hero——二分图匹配
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15563207.html
Copyright © 2011-2022 走看看