LOJ 6068「2017 山东一轮集训 Day4」棋盘
题意
一个 \(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」棋盘的更多相关文章
- Loj 6068. 「2017 山东一轮集训 Day4」棋盘
Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...
- [LOJ#6068]. 「2017 山东一轮集训 Day4」棋盘[费用流]
题意 题目链接 分析 考虑每个棋子对对应的横向纵向的极大区间的影响:记之前这个区间中的点数为 \(x\) ,那么此次多配对的数量即 \(x\) . 考虑费用流,\(S\rightarrow 横向区间 ...
- Loj #6069. 「2017 山东一轮集训 Day4」塔
Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...
- loj6068. 「2017 山东一轮集训 Day4」棋盘 二分图,网络流
loj6068. 「2017 山东一轮集训 Day4」棋盘 链接 https://loj.ac/problem/6068 思路 上来没头绪,后来套算法,套了个网络流 经典二分图 左边横,右边列 先重新 ...
- 「2017 山东一轮集训 Day4」棋盘(费用流)
棋盘模型 + 动态加边 #include<cstdio> #include<algorithm> #include<iostream> #include<cs ...
- Loj #6073.「2017 山东一轮集训 Day5」距离
Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...
- LOJ #6074. 「2017 山东一轮集训 Day6」子序列
#6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...
- loj #6077. 「2017 山东一轮集训 Day7」逆序对
#6077. 「2017 山东一轮集训 Day7」逆序对 题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ...
- LOJ #6119. 「2017 山东二轮集训 Day7」国王
Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ...
随机推荐
- nginx 1.12安装
准备工作 使用root用户安装. 到nginx官网下载Linux源码或者执行:wget http://nginx.org/download/nginx-1.12.2.tar.gz. 到pcre站点下载 ...
- Spring 配置文件AOP
1 <!-- 配置切面bean --> 2 <bean id="permAspect" class="com.tx.spring.aspect.Perm ...
- Centos-对比文件差异-diff
diff 比较文件差异 相关选项 -c 显示全部内容,并标记不同之处 -b 忽略行尾空格,并认为字符串中一个或多个空格视为相同 -r 当比较双方都是目录时,会比较子目录中的文件 -s 当两个文件相同 ...
- 灵感来袭,基于Redis的分布式延迟队列(续)
背景 上一篇(灵感来袭,基于Redis的分布式延迟队列)讲述了基于Java DelayQueue和Redis实现了分布式延迟队列,这种方案实现比较简单,应用于延迟小,消息量不大的场景是没问题的,毕竟J ...
- 浙大《数据结构》学习&练习(一)算法初步
1.数据结构是数据在计算机中的组织方式,类比图书在图书馆中的存储,应该如何分类,如何在书架上存取. 2.抽象数据结构是对一类的数据的一种组织方式的通用(抽象)描述,包括类型的名称,数据对象集和操作集. ...
- VSCode搭建golang环境
安装对应版本的Golang 略 VSCode安装对应 Go 插件 在应用商店安装即可:go VSCode安装 Go 工具: 在VSCode输入:Crtl + Shift + P 在弹出框输入:inst ...
- leaflet中如何优雅的解决百度、高德地图的偏移问题
话不多说,先上效果图 以前在做项目时,经常会听到客户说,你们这个地图是哪来的,太丑了,能不能换成百度地图--高德也行-- 大家生活中,基本上都已经习惯了使用百度地图和高德地图,而在做项目时,用这两个地 ...
- AntDesign初体验
AntDesign初体验 作为一个java开发也需要掌握一定的前端开发技能,毕竟靠人不如靠自己.再者,有时候一些小的改动自己就可以搞定了,就不用低三下四去求别人了: 安装Nodejs $ npm in ...
- 小试牛刀-hello,world!(第一个程序)
1.打开python的IDLE,启动Python解释器(按键盘的windows键,然后输入IDLE),在提示符下>>>输入命令:print("hello,world!&qu ...
- MeteoInfo脚本示例:读取FY3A AOD HDF文件
FY3A卫星有AOD产品数据,HDF格式,这里示例用MeteoInfo脚本程序读取和显示该类数据. 脚本程序如下: #----------------------------------------- ...