题意

一个 \(n\times n\) 的棋盘上面有若干障碍物。

定义两个棋子可以互相攻击当且仅当这两个棋子的横坐标或纵坐标相等而且中间不能隔着障碍物。(可以隔棋子)

有 \(q\) 次询问,每次询问你要回答在棋盘上摆 \(x\) 枚棋子最少互相能攻击到的棋子对数。

\(\texttt{Data Range:}1\leq n\leq 50,1\leq q\leq 10^4\)

题解

我咋连套路都不会了啊……

考虑二分图,将每一行每一列被 # 隔开的小段缩成一个点,对于每个可以放棋子位置像所属横纵坐标的小段连边。

但是一小段内放了 \(x\) 个棋子会对答案贡献 \(\binom{x}{2}\),我们要考虑如何最小化这个东西。

按照蓝书上的套路,考虑将一条边拆成流量为 \(1\),费用为 \(1,2,\cdots,x\) 的多条边,然后跑单路增广并且记录答案就行了。

注意到流量的意义就是放棋子的枚数,所以不能按照平常的写法来。

代码

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
const ll MAXN=1e4+51,inf=0x7fffffff;
struct Edge{
ll to,prev,flow,cost;
};
Edge ed[MAXN<<1];
ll n,source,sink,tot=1,maxFlow,minCost,limit,qcnt,curx;
char ch[51][51];
ll last[MAXN],vis[MAXN],dist[MAXN],res[MAXN],back[MAXN];
ll idx[51][51],idy[51][51],sz[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void addEdge(ll from,ll to,ll flow,ll cost)
{
ed[++tot].prev=last[from];
ed[tot].to=to;
ed[tot].flow=flow;
ed[tot].cost=cost;
last[from]=tot;
}
inline ll Min(ll x,ll y)
{
return x<y?x:y;
}
inline bool spfa()
{
queue<ll>q;
ll top,to;
memset(vis,0,sizeof(vis));
memset(dist,0x3f,sizeof(dist));
memset(back,0,sizeof(back));
dist[source]=0,vis[source]=1,q.push(source);
while(!q.empty())
{
top=q.front();
q.pop(),vis[top]=0;
for(register int i=last[top];i;i=ed[i].prev)
{
to=ed[i].to;
if(dist[to]>dist[top]+ed[i].cost&&ed[i].flow)
{
dist[to]=dist[top]+ed[i].cost,back[ed[i].to]=i;
if(!vis[to])
{
q.push(to),vis[to]=1;
}
}
}
}
if(dist[sink]!=0x3f3f3f3f)
{
return 1;
}
return 0;
}
inline ll MCMF()
{
ll flow;
while(spfa()&&maxFlow<limit)
{
for(register int i=back[sink];i;i=back[ed[i^1].to])
{
ed[i].flow--,ed[i^1].flow++;
}
res[++maxFlow]=(minCost+=dist[sink]);
}
return maxFlow;
}
int main()
{
n=read();
for(register int i=1;i<=n;i++)
{
scanf("%s",ch[i]+1);
for(register int j=1;j<=n;j++)
{
if(ch[i][j]=='.')
{
limit++;
}
}
}
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
if(ch[i][j]!='#')
{
idx[i][j]=(ch[i][j]==ch[i][j-1]?idx[i][j-1]:++sink);
}
}
}
curx=sink;
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
if(ch[j][i]!='#')
{
idy[j][i]=(ch[j][i]==ch[j-1][i]?idy[j-1][i]:++sink);
}
}
}
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
if(ch[i][j]!='#')
{
sz[idx[i][j]]++,sz[idy[i][j]]++;
}
}
}
sink++;
for(register int i=1;i<=curx;i++)
{
for(register int j=0;j<sz[i];j++)
{
addEdge(source,i,1,j),addEdge(i,source,0,-j);
}
}
for(register int i=curx+1;i<sink;i++)
{
for(register int j=0;j<sz[i];j++)
{
addEdge(i,sink,1,j),addEdge(sink,i,0,-j);
}
}
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
if(ch[i][j]=='.')
{
addEdge(idx[i][j],idy[i][j],1,0);
addEdge(idy[i][j],idx[i][j],0,0);
}
}
}
MCMF(),qcnt=read();
for(register int i=0;i<qcnt;i++)
{
printf("%d\n",res[read()]);
}
}

LOJ 6068「2017 山东一轮集训 Day4」棋盘的更多相关文章

  1. Loj 6068. 「2017 山东一轮集训 Day4」棋盘

    Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...

  2. [LOJ#6068]. 「2017 山东一轮集训 Day4」棋盘[费用流]

    题意 题目链接 分析 考虑每个棋子对对应的横向纵向的极大区间的影响:记之前这个区间中的点数为 \(x\) ,那么此次多配对的数量即 \(x\) . 考虑费用流,\(S\rightarrow 横向区间 ...

  3. Loj #6069. 「2017 山东一轮集训 Day4」塔

    Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...

  4. loj6068. 「2017 山东一轮集训 Day4」棋盘 二分图,网络流

    loj6068. 「2017 山东一轮集训 Day4」棋盘 链接 https://loj.ac/problem/6068 思路 上来没头绪,后来套算法,套了个网络流 经典二分图 左边横,右边列 先重新 ...

  5. 「2017 山东一轮集训 Day4」棋盘(费用流)

    棋盘模型 + 动态加边 #include<cstdio> #include<algorithm> #include<iostream> #include<cs ...

  6. Loj #6073.「2017 山东一轮集训 Day5」距离

    Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...

  7. LOJ #6074. 「2017 山东一轮集训 Day6」子序列

    #6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...

  8. loj #6077. 「2017 山东一轮集训 Day7」逆序对

    #6077. 「2017 山东一轮集训 Day7」逆序对   题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ...

  9. LOJ #6119. 「2017 山东二轮集训 Day7」国王

    Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ...

随机推荐

  1. MMC & SD 发展历史

    一.概述 MMC 卡和 SD 卡都是基于 Nand Flash 技术的移动存储卡. MMC(MultiMediaCard) 卡于 1997 年由西门子和 Sandisk 推出,SD (Secure D ...

  2. Centos-删除文件或目录-rm

    rm 删除目录或者文件,如果是链接文件,则只删除这个链接文件而不是链接指向的文件 相关选项 -r 递归删除目录 -f 忽略不存在提示和确认提示,本身确认提示系统默认添加-i参数 -i 删除文件前提示, ...

  3. UltraEdit文字编辑器菜单热键推荐

    键盘映射和自定义菜单热键 任何使用过UltraEdit / UEStudio一段时间的人都可能会告诉您,他们如此喜欢它的原因之一是"几乎所有东西都是可定制的".看一下产品鉴定,您会 ...

  4. 玩命学JVM(二)—类加载机制

    前言 Java程序运行图: 上一篇玩命学JVM(一)-认识JVM和字节码文件我们简单认识了 JVM 和字节码文件.那JVM是如何使用字节码文件的呢?从上图清晰地可以看到,JVM 通过类加载器完成了这一 ...

  5. 洛谷 P6851 【onu】贪心

    题目描述 题目传送门 分析 因为小 \(D\) 打出的牌与小 \(C\) 打出的牌花色必须相同,所以我们需要按照花色分类讨论 对于某一种花色 如果小 \(C\) 没有这种花色的牌但是小 \(D\) 有 ...

  6. 状压DP——【蜀传之单刀赴会】

    某王   老师今天考了一套三国题,AK了...就挑一道最恶心的题来写一写吧. 题目描述: [题目背景] 公元215年,刘备取益州,孙权令诸葛瑾找刘备索要荆州.刘备不答应,孙权极为恼恨,便派吕蒙率军取长 ...

  7. 通过VNC远程连接Linux实例

    无法使用Workbench和远程连接软件(例如PuTTY.Xshell.SecureCRT等)连接Linux实例时,您可以通过控制台的VNC远程连接实例,查看云服务器操作界面的实时状态. 前提条件 已 ...

  8. CyclicBarrier原来是这样的

    上一篇聊了一下Semaphore信号灯的用法及源码,这一篇来聊一下CyclicBarrier的用法及解析. 官网解释: 允许一组线程全部等待彼此达到共同屏障点的同步辅助.循环阻塞在涉及固定大小的线程方 ...

  9. 详解工程师不可不会的LRU缓存淘汰算法

    大家好,欢迎大家来到算法数据结构专题,今天我们和大家聊一个非常常用的算法,叫做LRU. LRU的英文全称是Least Recently Used,也即最不经常使用.我们看着好像挺迷糊的,其实这个含义要 ...

  10. 多测师讲解自动化测试 _RF连接数据库_高级讲师肖sir

    RF连接数据库:1.Connect To Database(连接数据库)2.Table Must Exist(表必须存在)3.Check If Exists In Database(查询某条件是否存在 ...