BZOJ 4823: [Cqoi2017]老C的方块

分析:

我觉得我的网络流白学了...QAQ...

其实数据范围本是无法用网络流跑过去的,然而出题者想让他跑过去,也就跑过去了...

看到题目其实感觉很麻烦,不知道从哪里入手,那么仔细观察所给出的有用信息...

我们考虑网格图是一个含有挡板的图,这个挡板的分布很有规律,大概是每一行的相邻两个挡板都隔了四个格子,并且奇数行的排列相同,偶数行的排列相同...

然后考虑不合法的方块形状有什么共同点:仔细观察就会发现,所有的不合法图形中,挡板的左边至少有一个格子,右边至少有一个格子,并且左边的格子连着一个格子,右边的的格子连着一个格子...也就是说,其实我们如果要使得整张图的所有方块构成的图形全部合法就要满足下图中如果挡板两边的紫色格子都有方块存放的话,那么,和这两个紫色格子相邻的色格子和黑色格子不能同时存在...

我们发现刚好相邻隔板之间的四个格子就是为不合法图案而设计的...

于是就变成了经典的限制问题...经典的最小割...

如果不考虑紫色的格子,那么这整张网格图就是一个二分图...我们给这张图染色...

那么对于所有的白点,我们连$<S,x,w[x]>$的边,对于所有的黑点我们连$<x,T,w[x]>$的边,然后因为要保证紫色格子周围黑白点不能同时存在,所以,对于所有的黑点,我们从紫色格子像黑点连$inf$的边,从白点像紫色格子连$inf$的边,然后因为我们两个紫色格子不同时存在的时候黑白点是可以同时存在的,所以两个紫色格子之间连上$min(w[x],w[y])$的边...然后求最小割就好了...

给出了不合法的图形,一定要找到不合法的方案的相同点,然后转换成一些基础的模型来解决...

对于网格图的问题,二分图应该是最常见的应用...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=100000+5,maxm=1000000+5;

int n,m,S,T,no,cnt;
int hd[maxn],fl[maxm],to[maxm],nxt[maxm],pos[maxn];
int mv[2][3][2]={-1,0,1,0,0,1,-1,0,1,0,0,-1};

vector<int> v[maxn];

map< pair<int,int>,pair<int,int> > mp;

inline void add(int x,int y,int s){
	fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
	fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
}

inline bool bfs(void){
	memset(pos,-1,sizeof(pos));
	int head=0,tail=0,q[maxn];
	q[0]=S;pos[S]=0;
	while(head<=tail){
		int top=q[head++];
		for(int i=hd[top];i!=-1;i=nxt[i])
			if(fl[i]&&pos[to[i]]==-1)
				pos[to[i]]=pos[top]+1,q[++tail]=to[i];
	}
	return pos[T]!=-1;
}

inline int find(int v,int f){
	if(v==T) return f;
	int res=0,t;
	for(int i=hd[v];i!=-1&&f>res;i=nxt[i])
		if(pos[to[i]]==pos[v]+1&&fl[i])
			t=find(to[i],min(f-res,fl[i])),res+=t,fl[i]-=t,fl[i^1]+=t;
	if(!res) pos[v]=-1;
	return res;
}

inline int dinic(void){
	int res=0,t;
	while(bfs())
		while(t=find(S,inf))
			res+=t;
	return res;
}

signed main(void){
#ifndef ONLINE_JUDGE
	freopen("block1.in","r",stdin);
#endif
	memset(hd,-1,sizeof(hd));
	scanf("%d%d%d",&m,&n,&no);S=0,T=no+1;
	for(int i=1,x,y,w;i<=no;i++)
		scanf("%d%d%d",&y,&x,&w),mp[make_pair(x,y)]=make_pair(i,w),v[x].push_back(y);
	for(int i=1;i<=n;i++)
		sort(v[i].begin(),v[i].end());
	for(int i=1,x,y,xw,yw,be,lx,ly,rx,ry;i<=n;i++)
		for(int j=0;j<v[i].size();j++){
			x=i,y=v[i][j];
			if((x&1)&&y%4==1){
				if(j<v[i].size()-1&&v[i][j+1]==y+1)
					add(mp[make_pair(x,y)].first,mp[make_pair(x,y+1)].first,min(mp[make_pair(x,y)].second,mp[make_pair(x,y+1)].second));
			}
			else if((x&1)&&y%4==2){
				for(int k=0;k<3;k++)
					if(mp.find(make_pair(x+mv[0][k][0],y+mv[0][k][1]))!=mp.end())
						add(mp[make_pair(x,y)].first,mp[make_pair(x+mv[0][k][0],y+mv[0][k][1])].first,inf);
			}
			else if((x&1)==0&&y%4==0){
				if(j>0&&v[i][j-1]==y-1)
					add(mp[make_pair(x,y)].first,mp[make_pair(x,y-1)].first,min(mp[make_pair(x,y)].second,mp[make_pair(x,y-1)].second));
			}
			else if((x&1)==0&&y%4==3){
				for(int k=0;k<3;k++)
					if(mp.find(make_pair(x+mv[1][k][0],y+mv[1][k][1]))!=mp.end())
						add(mp[make_pair(x,y)].first,mp[make_pair(x+mv[1][k][0],y+mv[1][k][1])].first,inf);
			}
			else if(((x+y)&1)&&(x&1)){
				for(int k=0;k<3;k++)
					if(mp.find(make_pair(x+mv[0][k][0],y+mv[0][k][1]))!=mp.end())
						add(mp[make_pair(x,y)].first,mp[make_pair(x+mv[0][k][0],y+mv[0][k][1])].first,inf);
				add(S,mp[make_pair(x,y)].first,mp[make_pair(x,y)].second);
			}
			else if((x&1)&&((x+y)&1)==0){
				for(int k=0;k<3;k++)
					if(mp.find(make_pair(x+mv[1][k][0],y+mv[1][k][1]))!=mp.end())
						add(mp[make_pair(x+mv[1][k][0],y+mv[1][k][1])].first,mp[make_pair(x,y)].first,inf);
				add(mp[make_pair(x,y)].first,T,mp[make_pair(x,y)].second);
			}
			else if(((x+y)&1)&&(x&1)==0){
				for(int k=0;k<3;k++)
					if(mp.find(make_pair(x+mv[1][k][0],y+mv[1][k][1]))!=mp.end())
						add(mp[make_pair(x,y)].first,mp[make_pair(x+mv[1][k][0],y+mv[1][k][1])].first,inf);
				add(S,mp[make_pair(x,y)].first,mp[make_pair(x,y)].second);
			}
			else{
				for(int k=0;k<3;k++)
					if(mp.find(make_pair(x+mv[0][k][0],y+mv[0][k][1]))!=mp.end())
						add(mp[make_pair(x+mv[0][k][0],y+mv[0][k][1])].first,mp[make_pair(x,y)].first,inf);
				add(mp[make_pair(x,y)].first,T,mp[make_pair(x,y)].second);
			}
		}
	printf("%d\n",dinic());
	return 0;
}

  



By NeighThorn

时间: 2024-08-01 10:45:55

BZOJ 4823: [Cqoi2017]老C的方块的相关文章

bzoj4823: [Cqoi2017]老C的方块(最小割)

4823: [Cqoi2017]老C的方块 题目:传送门 题解: 毒瘤题ORZ.... 太菜了看出来是最小割啥边都不会建...狂%大佬强强强   黑白染色?不!是四个色一起染,四层图跑最小割... 很惊奇的发现染完色之后只要是不喜欢的图形都一定可以由黄-->黑-->红-->绿 组成 那就很nice啦...兴高采烈的去敲代码...结果10^5*10^5???搞毛线...太弱了ORZ,又看了一波大佬的操作,用map存! woc...不谈了不谈了...撸撸撸(分情况分到想屎...虽然不多) 注

[bzoj4823][洛谷P3756][Cqoi2017]老C的方块

Description 老 C 是个程序员. 作为一个懒惰的程序员,老 C 经常在电脑上玩方块游戏消磨时间.游戏被限定在一个由小方格排成的R行C列网格上 ,如果两个小方格有公共的边,就称它们是相邻的,而且有些相邻的小方格之间的公共边比较特殊.特殊的公共边排 列得有很强的规律.首先规定,第1行的前两个小方格之间的边是特殊边.然后,特殊边在水平方向上每4个小方格为 一个周期,在竖直方向上每2个小方格为一个周期.所有的奇数列与下一列之间都有特殊边,且所在行的编号从左到 右奇偶交替.下图所示是一个R =

Bzoj4823 [Cqoi2017]老C的方块

没有题面,懒得手打 网络流 最小割 码农题(误) 一开始是冲着n<=5000的部分分写了网络流,结果神奇地发现似乎就是正解. 说好的dinic时间复杂度上界$O(V^2 E)$呢……网络流不愧是玄学算法. 放一张题目里的图 四种图案: 观察这四种图案和它们旋转/翻转以后的样子,可以发现一个共同点:每种图案都是由“中心一条蓝色边和它相邻的两个方块”,以及另外两个邻接的方块组成的 范围画出来就是这个样子: 可以发现“另外两个邻接的方块”肯定一个在蓝线左边一个在蓝线右边. 先说一种错误的想法: 将每个

【题解】CQOI2017老C的方块

网络流真的是一种神奇的算法.在一张图上面求感觉高度自动化的方案一般而言好像都是网络流的主阵地.讲真一开始看到这道题也有点懵,题面很长,感觉很难的样子.不过,仔细阅读了题意之后明白了:我们所要做的就是要用最小的代价,使得最后的图中不能出现给定的四种图案. 实际上之前做过一道非常毒瘤的网络流题目[无限之环].当时就思考了一下:为什么出题人规定不能旋转直线管子?原因就是因为这样的图建不出来,它与不具有其他的管子的特点.那么可以断定:给出的这四个图案必然也是非常特殊的图形,否则不会只有这四个/不会是这四

BZOJ 4824: [Cqoi2017]老C的键盘

Description 上一题弱化版,\(n\leqslant 100\) Solution 树形DP. Code /************************************************************** Problem: 4824 User: BeiYu Language: C++ Result: Accepted Time:188 ms Memory:18580 kb *******************************************

BZOJ 4822: [Cqoi2017]老C的任务

分析: 就是一个树状数组...把询问拆成四个... 考点大概就是把区间询问转化为前缀和相减... 代码: #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=100000+5; int n,m,tot,lenx,leny,mpx[maxn<<2],m

bzoj4822: [Cqoi2017]老C的任务

4822: [Cqoi2017]老C的任务 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 284  Solved: 152[Submit][Status][Discuss] Description 老 C 是个程序员. 最近老 C 从老板那里接到了一个任务--给城市中的手机基站写个管理系统.作为经验丰富的程序员,老 C 轻松 地完成了系统的大部分功能,并把其中一个功能交给你来实现.由于一个基站的面积相对于整个城市面积来说非常 的小,因此每个的基站

[BZOJ4824][CQOI2017]老C的键盘(树形DP)

4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 193  Solved: 149[Submit][Status][Discuss] Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也是一个程序员.有一天他悄悄潜入了老 C 的家中,想要看看这个 键盘究竟有何妙

[CQOI2017]老C的键盘

[CQOI2017]老C的键盘 题目描述 额,网上题解好像都是用的一大堆组合数,然而我懒得推公式. 设\(f[i][j]\)表示以\(i\)为根,且\(i\)的权值为\(j\)的方案数. 转移: \[ f[i][j]=\sum f[sn_1][k]*f[sn_2][q] \] 需要判断一下\(k,q\)与\(j\)的关系满不满足题意就行了. 但是这样的答案显然不对,因为有些权值可能多次出现. 换句话说,有些权值可能没有出现.所以我们就用那个经典的容斥,枚举颜色数上界. 设\(g[s]\)表示颜色