[2018湖南省队集训] 6.24 T1 marshland

题面在这里!

一开始感觉像一个类似二分图的最小割,于是成功跑偏2333333

很容易发现一个关键性质,‘L‘的两个角落在的偶数格 的行(或者列)的奇偶性一定不同。。。。

于是我们再把偶数格按照行(或者列)的奇偶性再细分成 两类,可以发现只有一个奇数格向旁边的两类偶数格都有空挡的话,才能放下一个L。

所以我们把放L看成网络中的一条流量,要经过三种点,于是对于奇数格拆点限流然后四列点直接跑最大费用最大流就行了。。。。

因为不用把m个L都放完,所以增广到 dis<0 的时候跳出就好啦。。。。

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
#define pb push_back
const int N=10005;

vector<int> g[N];
struct lines{
	int from,to,flow,cap,cost;
}l[N*73];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0},X,Y;
int S,T,t=-1,d[N],p[N],a[N],n,m,ans;
int val[55][55],id[55][55],cnt,k;
bool iq[N],ban[55][55];

inline void add(int from,int to,int cap,int cost){
	l[++t]=(lines){from,to,0,cap,cost},g[from].pb(t);
	l[++t]=(lines){to,from,0,0,-cost},g[to].pb(t);
}

inline bool SPFA(){
	memset(d,-0x3f,sizeof(d)),d[S]=0,p[S]=0;
	queue<int> q; q.push(S),a[S]=1<<30;
	int x,pre; lines e;

	while(!q.empty()){
		x=q.front(),q.pop();

		for(int i=g[x].size()-1;i>=0;i--){
			e=l[g[x][i]];
			if(e.flow<e.cap&&d[x]+e.cost>d[e.to]){
				d[e.to]=d[x]+e.cost;
				a[e.to]=min(a[x],e.cap-e.flow);
				p[e.to]=g[x][i];
				if(!iq[e.to]) iq[e.to]=1,q.push(e.to);
			}
		}

		iq[x]=0;
	}

	if(d[T]<0) return 0;

	if(a[T]>=m){ ans-=d[T]*m; return 0;}

	ans-=d[T]*a[T],m-=a[T];

	for(x=T;x!=S;x=l[pre].from){
		pre=p[x],l[pre].flow+=a[T];
		l[pre^1].flow-=a[T];
	}

	return 1;
} 

inline void solve(){
    S=0,T=cnt+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) if(!ban[i][j])
            if(i+j&1) add(id[i][j],id[i][j]+cnt,1,val[i][j]);
            else if(i&1){
            	add(S,id[i][j],1,0);
            	for(int u=0;u<4;u++){
            		X=i+dx[u],Y=j+dy[u];
            		if(id[X][Y]) add(id[i][j],id[X][Y],1,0);
				}
			}
			else{
            	add(id[i][j],T,1,0);
            	for(int u=0;u<4;u++){
            		X=i+dx[u],Y=j+dy[u];
            		if(id[X][Y]) add(id[X][Y]+cnt,id[i][j],1,0);
				}
			}

	while(SPFA());
}

int main(){
//	freopen("marshland.in","r",stdin);
//	freopen("marshland.out","w",stdout);

	scanf("%d%d%d",&n,&m,&k);

	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++){
		    scanf("%d",&val[i][j]);
			id[i][j]=++cnt,ans+=val[i][j];
        }

	while(k--) scanf("%d%d",&X,&Y),ban[X][Y]=1;

	solve();

	printf("%d\n",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/9245543.html

时间: 2024-11-09 09:58:55

[2018湖南省队集训] 6.24 T1 marshland的相关文章

2015湖南省队集训DAY3——Light

Light [问题描述] "若是万一琪露诺(俗称 rhl)进行攻击,什么都好,冷静地回答她的问题来吸引 对方表现出兴趣的话,那就慢慢地反问.在她考虑答案的时候,趁机逃吧.就算是很简 问题,她一定也答不上来." --<上古之魔书> 天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列 a[i],远 魔书上记载到:2 个位置的 graze 值为两者位置差与数值差的和: graze(x,y)=|x-y|+|a[x]-a[y]|. 要想破解天罚,就必须支持 2种操作(

湖南省队集训 -- 1

不知道为什么今天状态 大 好 可能是暴力分比较简单吧,来认真写一下总结 开局睡了1h-- 然后考虑a题,发现特殊性:因为最后的和一定是10^n的,最后两个数一定是后面一段全是0,前面一段两个数的和是⑨,0和⑨中间夹一对和为10 然后脑补正解不能,暴力枚举一下好像可以,就是判断是在不好写 然后考虑b题,看N^2算法,脑玩了一下发现距离是不会变得,如果钦定了一个点建站第1~n-1个点产生的权值是不会变得,最后一个点的距离也变不了,唯一得变量需求要乘距离,然后把剩下的不变量加起来,这就是个kx+b的形

【CodeVS 5032】【省队集训2016 Day5 T1】Play with array

一开始我用分块大法,分成$\sqrt{n}$块,每个块上维护一个Splay,然后balabala维护一下,时间复杂度是$O(n\sqrt{n}logn)$.后来对拍的时候发现比$O(n^2)$的暴力跑得还慢,TA爷说是Splay常数太大2333333 标算是块状链表,什么balabala比较基础地维护,卡着空间开2333333 我把块的大小设为$[\frac{\sqrt{n}}{2},\sqrt{n}×2)$,在codevs上TLE,,, 后来把块的大小改成了$[\sqrt{n},\sqrt{n

2015湖南省队集训DAY6——B题(BZOJ4179)

题面挺扯的,我就直接说人话算了. 题目大意:给你若干个病毒串,问你能不能构造出长度大于n的字符串使其中不出现任何一个字符串. 多组数据,总文件大小小于1M 题解: 联动:BZOJ2938 基本是原题,稍作了改动. 考虑ac自动机. 所求即为ac自动机中是否存在长度大于等于l的路径 先将所有的串插进去,然后构造失配指针. 显然的,插入后的末端节点肯定是不能经过的. 但仅这样显然是不可以的,我们考虑在匹配时,如果失配指针指向的节点是danger节点,那么这个节点也是不能经过的(显然). 所以考虑ac

JS省队集训记

不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么心态? T2 唉,感觉好像做过类似的? T3 唉,怎么是提交答案题…… 感觉前两题都会,信心大增,于是决定先码T2 码了一会,过了第二个样列,还有一个样例?咦怎么过不去? 纠结了一会发现——读错题了,啪啪啪,全写错了……立马就凌乱了 赶快做T1,结果发现meet in middle的空间复杂度好像炸

FJ省队集训DAY3 T1

思路:我们考虑如果取掉一个部分,那么能影响到最优解的只有离它最近的那两个部分. 因此我们考虑堆维护最小的部分,离散化离散掉区间,然后用线段树维护区间有没有雪,最后用平衡树在线段的左右端点上面维护最小的id 我讲的貌似不是很清楚.. 还有,蜜汁80分,打死也改不出来.. 1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algo

FJ省队集训DAY1 T1

题意:有一堆兔子,还有一个r为半径的圆,要求找到最大集合满足这个集合里的兔子两两连边的直线不经过圆. 思路:发现如果有两个点之间连边不经过圆,那么他们到圆的切线会构成一段区间,那么这两个点的区间一定会有交集,形如s0 s1 e0 e1 同样的,如果是n个点,那就是s0 s1 s2..sn e0 e1 e2.. en 因此,我们枚举那个起始点,然后对于其他点我们按照s排序,对于e做最长上升子序列即可.时间复杂度O(n^2 logn) 1 #include <cstdio> 2 #include

FJ省队集训DAY2 T1

思路:转换成n条三维空间的直线,求最大的集合使得两两有交点. 有两种情况:第一种是以某2条直线为平面,这时候只要统计这个平面上有几条斜率不同的直线就可以了 还有一种是全部交于同一点,这个也只要判断就可以了. 然后我并不能改出来,wa了好多个点 WA的程序: 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm&

FJ省队集训DAY5 T1

思路:考试的时候打了LCT,自以为能过,没想到只能过80.. 考完一想:lct的做法点数是100W,就算是nlogn也会T. 讲一下lct的做法把:首先如果一条边连接的两个点都在同一个联通块内,那么这条边对答案没有影响,可以忽略,因此,问题变成了每次询问两个点中路径上权值最大的边(这里的权值我们令它为加入这条边的时间),边我们用一个点连接两个端点来表示. 正解:由于是无根树,因此我们用并查集按秩合并,每次把小的加到大的里面去,询问的时候暴力走lct查找最大即可. 1 #include<cstdi