QOJ 1197

qoj 1197. Draw in Straight Lines

[!note]

[!tip]

因为不允许先染 \(0\) 在染 \(1\),所以一定是先染黑色,再染白色。

所以我们着色的过程(最优解)一定遵循以下步骤:

  1. 染黑色
  2. 染白色
  3. 单点染色

[!tip]

对于一个格子,不可能存在它被同一方向的染色染两次。

证明:

根据上面的 观察,我们可以尝试计算答案的组成。

先考虑答案中贡献为 \(C\) 部分,它分两种情况:

  1. 最后应该是 \(0\),但是操作完后 \(1\)。
  2. 最后应该是 \(1\),但操作完后是 \(0\)。

当发生这两种情况时,答案要被 \(C\) 贡献。

接下来考虑 \(Ax+B\) 的贡献情形:

按照以往的做题经验,一次贡献为 \(Ax+B\) 的形式,往往可以把 \(A\) 进行贡献延迟计算,和 \(B\) 放在一个标志物上进行计算。那么我们 尝试把 \(B\) 放在染色的端点上进行计算,为了方便,我们将 从上往下和从左往右 的两种染色方式的 \(B\) 贡献 放在最上面和最左面进行计算。

但是这个的正确性需要每个位置 最多只被竖着染一次,横着染一次(即不会同向覆盖),显然这个在这道题目中是成立的(参见关键观察 \(2\))。

接下来考虑 最小割模型,套路地,先设出正常的布尔变量:

  1. \((i,j)\) 是否被 从上往下的 \(0\) 覆盖过,记为 \((i,j,1)\)。
  2. \((i,j)\) 是否被 从左往右的 \(0\) 覆盖过,记为 \((i,j,2)\)。
  3. \((i,j)\) 是否被 从上往下的 \(1\) 覆盖过,记为 \((i,j,3)\)。
  4. \((i,j)\) 是否被 从左往右的 \(1\) 覆盖过,记为 \((i,j,4)\)。

接下来 验证 二元限制是不是一个限制为 \(true\) 且 另一个限制为 \(false\):

  1. \((i,j,1) \wedge ¬(i-1,j,1)\) 则有 \(B\) 的 代价。(没反)
  2. \((i,j,2) \wedge ¬(i,j-1,2)\) 则有 \(B\) 的 代价。(没反)
  3. \((i,j,3) \wedge ¬(i-1,j,3)\) 则有 \(B\) 的 代价。(没反)
  4. \((i,j,4) \wedge ¬(i,j-1,4)\) 则有 \(B\) 到 代价。(没反)
  5. \((i,j)\) 这个格子的最终状态是 \(0\),则 \((i,j,3) \wedge (i,j,4)\) 有 \(\infty\) 的 代价。(反了)
  6. \((i,j)\) 这个格子的最终状态是 \(1\),则 \((i,j,1) \wedge (i,j,2)\) 有 \(\infty\) 的 代价。(反了)
  7. \((i,j,2) \wedge (i,j,4)\) 有 \(\infty\) 的 代价。(反了)
  8. \((i,j,1) \wedge (i,j,3)\) 有 \(\infty\) 的 代价。(反了)

解释:

  • 第五、六种情况是因为最后不可能被染成 \(0\)(一个格子最多被染 \(2\) 次)
  • 第七、八种情况是因为 关键观察 \(2\),不可能发生这种情况,所以代价为 \(\infty\)。
  1. \((i,j)\) 这个格子的最终状态是 \(0\),则 \((i,j,3) \wedge ¬(i,j,2)\) 有 \(C\) 的 代价。(没反)
  2. \((i,j)\) 这个格子的最终状态是 \(0\),则 \((i,j,4) \wedge ¬(i,j,1)\) 有 \(C\) 的 代价。(没反)
  3. \((i,j)\) 这个格子的最终状态是 \(1\),则 \(¬(i,j,3) \wedge ¬(i,j,4)\) 有 \(C\) 的 代价。(反了)

现在有一些 限制 没有反,而有一些 限制 反了,那么 通过 简单、细致、认真、富有想象力和幻想力的观察,我们发现只要翻转 \(1,4\) 限制即可。

时间复杂度:\(\mathcal O(最大流)\)。

代码:

const int N=55,M=5e5+50,inf=2147483647,mod=998244353;
int cas;
int n,m,A,B,C,S,T,tot,cnt=1;
char s[N][N];
int black_line_yes[N][N],black_row_no[N][N],white_line_no[N][N],white_row_yes[N][N];
int head[M],cur[M],dep[M];
struct edge{
    int to,nxt,flow;
}e[M];
void add(int u,int v,int flow)
{
    e[++cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].flow=flow;
}
bool bfs()
{
	for(int i=0;i<=T;i++)dep[i]=0;
	queue<int> q;q.push(S);dep[S]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(!dep[v]&&e[i].flow)
			{
				dep[v]=dep[u]+1;
				q.push(v);
			}
		}
	}
	return dep[T];
}
int dfs(int u,int flow)
{
	if(u==T||!flow)return flow;
	int res=0;
	for(int& i=cur[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(dep[v]!=dep[u]+1||!e[i].flow)continue;
		int f=dfs(v,min(flow-res,e[i].flow));
		if(f)
		{
			res+=f;
			e[i].flow-=f;e[i^1].flow+=f;
		}else dep[v]=-1;
		if(res==flow)return res;
	}
	return res;
}
int dinic()
{
	int maxflow=0;
	while(bfs())
	{
		for(int i=0;i<=T;i++)cur[i]=head[i];
		maxflow+=dfs(S,inf);
	}
	return maxflow;
}
void solve()
{
    cin>>n>>m>>A>>B>>C;
    for(int i=1;i<=n;i++)cin>>(s[i]+1);
    S=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            black_line_yes[i][j]=++tot;//(i,j,4)
			black_row_no[i][j]=++tot;//(i,j,3)
			white_line_no[i][j]=++tot;//(i,j,2)
			white_row_yes[i][j]=++tot;//(i,j,1)
        }
    }
    T=++tot;
    for(int i=1;i<=m;i++)white_row_yes[n+1][i]=T,black_line_yes[n+1][i]=T;
    for(int i=1;i<=n;i++)black_line_yes[i][m+1]=T,white_row_yes[i][m+1]=T;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            add(white_row_yes[i][j],T,A);add(T,white_row_yes[i][j],0);
            add(black_line_yes[i][j],T,A);add(T,black_line_yes[i][j],0);
            add(S,white_line_no[i][j],A);add(white_line_no[i][j],S,0);
            add(S,black_row_no[i][j],A);add(black_row_no[i][j],S,0);

            add(white_row_yes[i][j],white_row_yes[i+1][j],B);add(white_row_yes[i+1][j],white_row_yes[i][j],0);
            add(black_line_yes[i][j],black_line_yes[i][j+1],B);add(black_line_yes[i][j+1],black_line_yes[i][j],0);
            add(white_line_no[i][j+1],white_line_no[i][j],B),add(white_line_no[i][j],white_line_no[i][j+1],0);
            add(black_row_no[i+1][j],black_row_no[i][j],B),add(black_row_no[i][j],black_row_no[i+1][j],0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='.')//如果 (i,j) 是白色
            {
                add(black_line_yes[i][j],white_row_yes[i][j],C);add(white_row_yes[i][j],black_line_yes[i][j],0);
                add(white_line_no[i][j],black_row_no[i][j],C);add(black_row_no[i][j],white_line_no[i][j],0);
                add(black_line_yes[i][j],black_row_no[i][j],inf);add(black_row_no[i][j],black_line_yes[i][j],0);
            }
            else
            {
                add(black_row_no[i][j],black_line_yes[i][j],C);add(black_line_yes[i][j],black_row_no[i][j],0);
                add(S,white_line_no[i][j],inf);add(white_line_no[i][j],S,0);
                add(white_row_yes[i][j],T,inf);add(T,white_row_yes[i][j],0);
            }
        }
    }
    cout<<dinic()<<endl;
}
signed main()
{
    cas=1;
    while(cas--)solve();
    return 0;
}
posted @ 2025-07-26 17:45  _apologize  阅读(53)  评论(0)    收藏  举报