SCOI2015 day1

第二次做这套题了。。结果还是太naive
T1
一个矩阵 n*m,选出n个数并且不在同一行同一列
二份答案转换为判定问题,看看够不够k个
如果在一行在一列有冲突怎么解决呢?网络流经典模型!
如果一个符合要求,连接该点所在的行和列即可
最大流满流的话就是合法的答案
T2
当年觉得需要离散化呢,现在写一下发现是想多了
维护f[i][j],表示i个人向前2^j传到达的人
在环上?倍长!
边界有问题?加哨兵!
由于编号问题,makedata没写好导致炸0....下次注意
T3
考察0-1和i-i+1
对于一个点,如果这个点与0-1的面积比i-i+1小,我们称这个点为合法点
显然我们可以很简单的拿到2个合法点(连接0和i+1,在这条线上二分,1和i一样)
然后可以证明这两个点的连线的靠近0-1一侧都是合法点(证明可以作垂线然后相识做)

这样对于每个i-i+1都可以得到一条合法线,那么半平面交就OK

代码

T1

//Copyright(c)2016 liuchenrui
#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 1000000000
using namespace std;
inline void splay(int &v){
	v=0;char c=0;int p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
int a[255][255];
struct Edge{
	int to,next,flow;
}edge[1000010];
int first[600],size;
int deep[600],dl[600];
void addedge(int x,int y,int z){
	size++;
	edge[size].to=y;
	edge[size].next=first[x];
	first[x]=size;
	edge[size].flow=z;
}
int dfs(int now,int flow,int aim){
	if(now==aim)return flow;
	int F=0;
	for(int u=first[now];u&&flow;u=edge[u].next){
		if(deep[edge[u].to]==deep[now]+1&&edge[u].flow){
			int tmp=dfs(edge[u].to,min(flow,edge[u].flow),aim);
			F+=tmp;edge[u].flow-=tmp;edge[u^1].flow+=tmp;flow-=tmp;
		}
	}
	if(!F)deep[now]=-5;
	return F;
}
bool bfs(int S,int T){
	memset(deep,0,sizeof(deep));
	dl[1]=S;deep[S]=1;
	int head=0,tail=1;
	while(head!=tail){
		int v=dl[++head];
		for(int u=first[v];u;u=edge[u].next){
			if(!deep[edge[u].to]&&edge[u].flow){
				dl[++tail]=edge[u].to;
				deep[edge[u].to]=deep[v]+1;
			}
		}
	}
	return deep[T];
}
int maxflow(int S,int T){
	int ret=0;
	while(bfs(S,T)){
		ret+=dfs(S,inf,T);
	}
	return ret;
}
int n,m,k;
int check(int mid){
	memset(first,0,sizeof first);size=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]<=mid){
				addedge(i,j+250,1);
				addedge(j+250,i,0);
			}
		}
	}
	for(int i=1;i<=n;i++){
		addedge(0,i,1);
		addedge(i,0,0);
	}
	for(int j=1;j<=m;j++){
		addedge(j+250,550,1);
		addedge(550,j+250,0);
	}
	int tmp=maxflow(0,550);
	return tmp;
}
int main(){
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	splay(n),splay(m),splay(k);
	k=n-k+1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			splay(a[i][j]);
		}
	}
	int l=0,r=1000000009;
	while(l!=r){
		int mid=l+r>>1;
		if(check(mid)<k)l=mid+1;
		else r=mid;
	}
	printf("%d\n",l);
}

T2

//Copyright(c)2016 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
inline void splay(int &v){
	v=0;char c=0;int p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
struct SCOI2015{
	int l,r;
	int id;
}s[200010],e[200010];
int Ans[200010];
bool comp(const SCOI2015 &a,const SCOI2015 &b){
	return a.l<b.l;
}
bool in(int now,int l,int r){
	if(now==1000000001)return false;
	if(l<=r){
		if(now>=l && now<=r)return true;
		else return false;
	}
	else{
		if(now>=l || now<=r)return true;
		else return false;
	}
}
int p[400010];
int t[400010][21];
int A[400010];
int n,m;
int main(){
	freopen("flag.in","r",stdin);
	freopen("flag.out","w",stdout);
	splay(n),splay(m);
	for(int i=1;i<=n;i++){
		splay(e[i].l),splay(e[i].r);
		e[i].id=i;
	}
	sort(e+1,e+n+1,comp);
	for(int i=1;i<=n;i++){
		s[i].l=e[i].l,s[i].r=e[i].r;
		s[i].id=i;
	}
	sort(s+1,s+n+1,comp);
	for(int i=1;i<=n;i++){
		p[i]=p[i+n]=s[i].id;
	}
	p[n+n+1]=n+1;
	s[n+1].l=1000000001,s[n+1].r=1000000001;
	int now=p[1];
	for(int i=1;i<=n<<1;i++){
		while(in(s[p[now]].l,s[p[i]].l,s[p[i]].r)&&now!=i+n){
			now++;
		}
		t[i][0]=now-1;
	}
	for(int k=1;k<=20;k++){
		for(int i=1;i<=n<<1;i++){
			t[i][k]=t[t[i][k-1]][k-1];
		}
	}
	for(int i=1;i<=n;i++){
		int aim=i+n,now=i,ans=1;
		for(int j=20;j>=0;j--){
			if(t[now][j]<aim){
				now=t[now][j];
				ans+=(1<<j);
			}
		}
		Ans[s[i].id]=ans;
	}
	for(int i=1;i<=n;i++){
		//printf("%d ",Ans[i]);
		A[e[i].id]=Ans[i];
	}
	for(int i=1;i<=n;i++){
		printf("%d ",A[i]);
	}
}
T3没调出来QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值