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  阅读(4)  评论(0)    收藏  举报