[BZOJ 2756] 奇怪的游戏
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2756
Algorithm:
比较新颖的题目
首先发现是对矩阵中相邻两数进行操作 <-----> 想到黑白染色
于是Delta(BlackSum)=Delta(WhiteSum)
由于最后要变成同一个数X,
那么在BlackNum=WhiteNum时,
1、如果WhiteSum!=BlackSum,显然无解
2、如果WhiteSum==BlackSum时,由于矩阵能被1*2的矩形完全覆盖,那么X是否满足要求是具有单调性的
于是我们二分X,进行判断即可
在WhiteNum!=BlackNum时,
显然可以得到X∗WhiteNum−WhiteSum=X∗BlackNum−BlackSum
移项后显然可以化简出X=(BlackSum−WhiteSum) / (BlackNum−WhiteNum)
验证这个X即可
最大问题,如何判断X是否可行,
一开始得出的性质:Delta(BlackSum)=Delta(WhiteSum),符合流守恒性(流入和流出量相同)
于是我们进行可以将黑点看作一边,而将白点看作另外一边,网络流建图:
S-->白点,CAP为X-val[i][j]
黑点-->T,CAP为X-val[i][j]
相邻的白点-->黑点,CAP为INF
判断能否满流即可
Code:
#include <bits/stdc++.h> using namespace std;
#define pos(x,y) (x-1)*m+y
typedef pair<int,int> P;
typedef long long ll;
const int MAXN=;
const ll INF=1ll<<; ll test,n,m,col[MAXN][MAXN],dat[MAXN][MAXN],iter[MAXN*MAXN],level[MAXN*MAXN];
ll sum1,sum2,cnt1,cnt2,mx,S,T; struct edge
{
ll to,cap,rev;
};
vector<edge> G[MAXN*MAXN]; void add_edge(int from,int to,ll cap)
{
G[from].push_back(edge{to,cap,G[to].size()});
G[to].push_back(edge{from,,G[from].size()-});
} bool bfs()
{
memset(level,-,sizeof(level));
queue<int> que;que.push(S); level[S]=;
while(!que.empty())
{
int t=que.front();que.pop();
for(int i=;i<G[t].size();i++)
{
edge e=G[t][i];
if(e.cap> && level[e.to]==-)
{
level[e.to]=level[t]+;
que.push(e.to);
}
}
}
} ll dfs(int cur,int T,ll f)
{
if(cur==T) return f; for(ll &i=iter[cur];i<G[cur].size();i++)
{
edge &e=G[cur][i];
if(level[e.to]==level[cur]+ && e.cap>)
{
ll d=dfs(e.to,T,min(f,e.cap));
if(d>)
{
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return ;
} ll dinic()
{
ll ret=;
while(true)
{
memset(iter,,sizeof(iter));
bfs();if(level[T]==-) break;
ll f;
while((f=dfs(S,T,INF))>) ret+=f; //这里括号不能排错啊
}
return ret;
} int dx[]={,,,-};
int dy[]={,-,,}; bool check(ll tar)
{
S=;T=n*m+;ll ret=;
for(int i=;i<MAXN*MAXN;i++) G[i].clear();
for(int i=;i<=n;i++) //建图
for(int j=;j<=m;j++)
{
if(col[i][j]) add_edge(S,pos(i,j),tar-dat[i][j]),ret+=tar-dat[i][j];
else {add_edge(pos(i,j),T,tar-dat[i][j]);continue;}
for(int k=;k<;k++)
{
int fx=i+dx[k],fy=j+dy[k];
if(fx>= && fx<=n && fy>= && fy<=m)
add_edge(pos(i,j),pos(fx,fy),INF);
}
} ll MAXFLOW=dinic(); //dinic
return (ret==MAXFLOW);
} int main()
{
cin >> test;
while(test--)
{
cin >> n >> m;mx=;
cnt1=cnt2=sum1=sum2=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
cin >> dat[i][j];
col[i][j]=(i+j)&;mx=max(mx,dat[i][j]);
if(col[i][j]) sum1+=dat[i][j],cnt1++;
else sum2+=dat[i][j],cnt2++;
} if(cnt1!=cnt2)
{
ll tar=(sum1-sum2)/(cnt1-cnt2);
if(tar<mx){puts("-1");continue;} if(check(tar))
{
cout << tar*cnt1-sum1 << endl;
continue;
}
puts("-1");
}
else
{
if(sum1!=sum2){puts("-1");continue;} ll l=mx,r=INF;
while(l<=r)
{
ll mid=(l+r)>>;
if(check(mid)) r=mid-;
else l=mid+;
}
if(r==INF) puts("-1"); //如果到INF都无解,则说明就是无解,要特判,但BZOJ上数据比较水(黄学长的标程是错的)
else cout << 1ll*(l*cnt1-sum1) << endl;
}
}
return ;
}
Review:
1、看到这种对相邻格子同时操作的题目,想到黑白染色
2、求极值,观察值的可行性是否具有单调性,从而能否二分
3、当数据能分为两组,且具有流守恒性时
考虑使用网络流
4、调试:
(1)有多个括号要留心每个括号的位置啊,多看几遍
while((f=dfs(S,T,INF))>)
这里的>0一开始放到第2个括号里了,结果f每次就都是0或1了……囧,调了1h
(2)像网络流这样执行过一边就会对原数组产生影响的模块,
执行过一次后想调试/再次调用时,不能再执行一遍,将第一次结果存储即可
(3)由于模板中大部分数据都是int,如果有long long时要特别注意修改原模板中的int
惨案:
void add_edge(int from,int to,ll cap)
[BZOJ 2756] 奇怪的游戏的更多相关文章
- bzoj 2756奇怪的游戏
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MB Description Blinke 最近喜欢上一个奇怪的游戏. 这个游戏 ...
- BZOJ 2756 奇怪的游戏(最大流)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2756 题意:在一个 N*M 的棋盘上玩,每个格子有一个数.每次 选择两个相邻的格子,并使 ...
- 【BZOJ】【2756】【SCOI2012】奇怪的游戏
网络流-最大流 这题……建模部分先略过 这道题是会卡时限的T_T俺的Dinic被卡了,在此放几篇很棒的讲网络流算法的文章,至于大家耳熟能详的论文就不放了…… http://www.cppblog.co ...
- BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 3352 Solved: 919[Submit][Stat ...
- BZOJ 2756: [SCOI2012]奇怪的游戏 网络流/二分
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1594 Solved: 396[Submit][Stat ...
- BZOJ 2756 SCOI2012 奇怪的游戏 最大流
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756 Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N ...
- bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流
2756:[SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4926 Solved: 1362[Submit][Stat ...
- bzoj 2756: [SCOI2012]奇怪的游戏
Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...
- BZOJ 2756 【SCOI2012】 奇怪的游戏
题目链接:奇怪的游戏 一开始这道题想岔了……想到黑白染色后对总格子数按奇偶性分类讨论,然后没发现奇数个格子的可以直接解方程…… 首先可以发现每次操作是给相邻的两个格子权值加一,因此我们把棋盘黑白染色后 ...
随机推荐
- Website Collection
前一百个卡特兰数 Candy?的博弈论总结 杜教筛资料 线性基资料 (ex)BSGS资料 斐波那契数列前300项 斯特林数 STL标准库-容器-unordered_set C++ unordered_ ...
- 【NOIP模拟赛】 permutation 数学(打表)
biubiu~~~ 这道题卡读题卡得很死......首先他告诉我们读循环的时候要顺着圈读,然后又说这个圈在数列上要以最大数开始读,而且以这样的循环的首数排序,得到的序列与原序列一样那么他就是可行序列, ...
- 在Eclipse上使用egit插件通过ssh协议方式上传项目代码的具体步骤
在Eclipse上使用egit插件通过ssh协议方式上传项目代码 前戏: 使用ssh方式可以不通过https协议,避免直接提供账号密码的方式上传项目到git在线服务器,如Bitbucket.GitHu ...
- 创建dll
在制作dll的时候,如果全局变量不导出,而函数调用中,包含了全局变量,那么会出现全局变量没有值的问题. add.c #pragma once //强制无签名utf-8 #include "a ...
- 深入理解Java虚拟机—内存管理机制
前面说过了类的加载机制,里面讲到了类的初始化中时用到了一部分内存管理的知识,这里让我们来看下Java虚拟机是如何管理内存的. 先让我们来看张图 有些文章中对线程隔离区还称之为线程独占区,其实是一个意思 ...
- HDU1166 敌兵布阵(树状数组实现
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- MVC 自定义HtmlHelper帮助类型之分页
方法一: 在项目中增加App_Code文件夹,新增一个MyHtmlper.cshtml视图文件 写入代码: @helper Pagger(int pageIndex, int pageCount) { ...
- Git菜鸟
1.git 和svn的差异 git和svn 最大的差异在于git是分布式的管理方式而svn是集中式的管理方式.如果不习惯用代码管理工具,可能比较难理解分布式管理和集中式管理的概念.下面介绍两种工具的工 ...
- 51nod加农炮
这道题维护一下前缀最大值然后二分答案就好了哇 233 #include<cstdio> #include<cstring> #include<algorithm> ...
- 【洛谷 P3469】[POI2008]BLO-Blockade(割点)
题目链接 题意:一个无向联通图,求删去每个点及其所有边后有多少有序点对的连通性发生了变化. Tarjan求割点的例题.. 如果当前点不是割点,那么它对整个图的连通性不产生影响,只有自己与其他\(n-1 ...