20200607 练习:CQOI2017day2(二维数点)(网络流)(树形dp)

T1 P3755 [CQOI2017]老C的任务

思路:
二维数点
离线后线段树维护

代码:

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
#define lch p<<1
#define rch p<<1|1

inline int in{
	int s=0,f=1;char x;
	for(x=getchar();x<'0'||x>'9';x=getchar())	if(x=='-')	f=-1;
	for( ;x>='0'&&x<='9';x=getchar())	s=(s*10)+(x&15);
	return f==1?s:-s;
}

const int A=5e5+5;
int n,m;
struct Point{
	int x,y,val;
}pt[A];
struct Qurey{
	int x,y1,y2,id,opt;
}qur[A];
inline bool cmp1(const Point u,const Point v){
	return u.x<v.x;
}
inline bool cmp2(const Qurey u,const Qurey v){
	return u.x<v.x;
}

int nw[A],tot,len;

struct Tree{
	int l,r,val;
}tr[4*A];
int ans[A];

inline void pushup(int p){
	tr[p].val=tr[lch].val+tr[rch].val;
	return;
}

inline void build(int p,int l,int r){
	tr[p].l=l,tr[p].r=r;
	if(l==r){
		tr[p].val=0;
		return;
	}
	int mid=(l+r)>>1;
	build(lch,l,mid),build(rch,mid+1,r);
	pushup(p); 
	return;
}

inline void add(int p,int w,int val){
	if(tr[p].l==tr[p].r){
		tr[p].val+=val;
		return;
	}
	int mid=(tr[p].l+tr[p].r)>>1;
	if(w<=mid)	add(lch,w,val);
	else	add(rch,w,val);
	pushup(p);
	return;
}

inline int qurey(int p,int l,int r){
	if(tr[p].l>=l&&tr[p].r<=r)	return tr[p].val;
	int ans=0;
	int mid=(tr[p].l+tr[p].r)>>1;
	if(l<=mid)	ans+=qurey(lch,l,r);
	if(r>=mid+1)	ans+=qurey(rch,l,r);
	pushup(p);
	return ans;
}


inline void scan(){
	n=in,m=in;
	for(int i=1;i<=n;i++){
		pt[i].x=in,pt[i].y=in,pt[i].val=in;
		nw[++tot]=pt[i].y;
	}
	for(int i=1;i<=m;i++){
		int a=in,b=in,c=in,d=in;
		a--;
		qur[2*i-1].x=a,qur[2*i-1].y1=b,qur[2*i-1].y2=d,qur[2*i-1].id=i,qur[2*i-1].opt=-1;
		qur[2*i].x=c,qur[2*i].y1=b,qur[2*i].y2=d,qur[2*i].id=i,qur[2*i].opt=1;
		nw[++tot]=b,nw[++tot]=d;
	}
	sort(nw+1,nw+1+tot);
	len=unique(nw+1,nw+1+tot)-(nw+1);
	for(int i=1;i<=n;i++)
		pt[i].y=lower_bound(nw+1,nw+1+len,pt[i].y)-nw;
	for(int i=1;i<=2*m;i+=2){
		qur[i].y1=lower_bound(nw+1,nw+1+len,qur[i].y1)-nw;
		qur[i].y2=lower_bound(nw+1,nw+1+len,qur[i].y2)-nw;
		qur[i+1].y1=qur[i].y1,qur[i+1].y2=qur[i].y2;
	}
	sort(pt+1,pt+1+n,cmp1);
	sort(qur+1,qur+1+2*m,cmp2);
	return;
}

inline void work(){
	build(1,1,len);
	int pos=1;
	for(int i=1;i<=2*m;i++){
		while(pos<=n&&pt[pos].x<=qur[i].x){
			add(1,pt[pos].y,pt[pos].val);
			pos++;
		}
		if(qur[i].opt==-1){
			ans[qur[i].id]-=qurey(1,qur[i].y1,qur[i].y2);
		}
		else{
			ans[qur[i].id]+=qurey(1,qur[i].y1,qur[i].y2);
		}
	}
	for(int i=1;i<=m;i++)	printf("%lld\n",ans[i]);
	return;
}

signed main(){
	scan(); 
	work();
	return 0;
}

T2 P3756 [CQOI2017]老C的方块

思路:

因为是网格图,所以考虑染色将格子分类

发现奇偶行,奇偶列分别是不同的

那么有四种格子,考虑用四种颜色染色

在这里插入图片描述

发现题目中给的四种图形都有相同性质

每个图形必定包含四种颜色,并且红色和蓝色必定相邻

于是破环一个图形至少会破坏一种颜色

考虑最小割

对于一个图形,需要只连一条通路

发现黄色和蓝不直接相邻,绿色和红色不直接相邻,并且红色和蓝色必定相邻

于是考虑黄色连向红色连向蓝色连向绿色

在这里插入图片描述

将红蓝间的边权赋为红蓝点权的小值,黄红边权赋为 INF,蓝绿边权赋为 INF

源点向黄点连边,边权为黄点点权,绿点向汇点连边,边权为绿点点权

跑最小割即可

代码:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
#define in Read()
#define int long long
#define re register
#define S 0
#define T (n+1)

inline char ch(){
	static char buf[1<<21],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}

inline int in{
	int s=0,f=1;char x;
	for(x=ch();x<'0'||x>'9';x=ch())	if(x=='-')	f=-1;
	for( ;x>='0'&&x<='9';x=ch())	s=(s*10)+(x&15);
	return f==1?s:-s;
}

const int A=2e5+5;
const int B=6e6+5;
const int INF=1e18;
int N,M,n;
int p1[A],p2[A];
int val[A];
tr1::unordered_map <int,int> ma;
inline int d(int x,int y){
	return (x-1)*max(N,M)+y;
}
int maxflow=0;
int head[A],tot_road=1;
struct Road{
	int nex,to,w;
}road[B];
inline void ljb(int x,int y,int w){
	road[++tot_road]={head[x],y,w};head[x]=tot_road;
}
int dep[A],sum[A];

inline void scan(){
	N=in,M=in,n=in;
	for(re int i=1;i<=n;++i){
		int u=in,v=in;
		p1[i]=u,p2[i]=v,val[i]=in;
		ma.insert(pair<int,int>(d(u,v),i));
	}
	return;
}

inline void red(int x,int y){
	if(x%4==0){
		if(x-1>=1&&ma.find(d(x-1,y))!=ma.end()){
			int u=ma[d(x,y)],v=ma[d(x-1,y)];
			ljb(u,v,min(val[u],val[v])),ljb(v,u,0);
		}
	}
	else{
		if(x+1<=N&&ma.find(d(x+1,y))!=ma.end()){
			int u=ma[d(x,y)],v=ma[d(x+1,y)];
			ljb(u,v,min(val[u],val[v])),ljb(v,u,0);
		}
	}
	return;
}
inline void blu(int x,int y){
	int u=ma[d(x,y)],v;
	if(y+1<=M&&ma.find(d(x,y+1))!=ma.end()){
		v=ma[d(x,y+1)];
		ljb(u,v,INF),ljb(v,u,0);
	}
	if(y-1>=1&&ma.find(d(x,y-1))!=ma.end()){
		v=ma[d(x,y-1)];
		ljb(u,v,INF),ljb(v,u,0);
	}
	if(x%4==2){
		if(x+1<=N&&ma.find(d(x+1,y))!=ma.end()){
			v=ma[d(x+1,y)];
			ljb(u,v,INF),ljb(v,u,0);
		}
	}
	else{
		if(x-1>=1&&ma.find(d(x-1,y))!=ma.end()){
			v=ma[d(x-1,y)];
			ljb(u,v,INF),ljb(v,u,0);
		}
	}
	return;
}
inline void yel(int x,int y){
	int u=ma[d(x,y)],v;
	ljb(S,u,val[u]),ljb(u,S,0);
	if(y+1<=M&&ma.find(d(x,y+1))!=ma.end()){
		v=ma[d(x,y+1)];
		ljb(u,v,INF),ljb(v,u,0);
	}
	if(y-1>=1&&ma.find(d(x,y-1))!=ma.end()){
		v=ma[d(x,y-1)];
		ljb(u,v,INF),ljb(v,u,0);
	}
	if(x%4==0){
		if(x+1<=N&&ma.find(d(x+1,y))!=ma.end()){
			v=ma[d(x+1,y)];
			ljb(u,v,INF),ljb(v,u,0);
		}
	}
	else{
		if(x-1>=1&&ma.find(d(x-1,y))!=ma.end()){
			v=ma[d(x-1,y)];
			ljb(u,v,INF),ljb(v,u,0);
		}
	}
	return;
}
inline void gre(int x,int y){
	int u=ma[d(x,y)];
	ljb(u,T,val[u]),ljb(T,u,0);
	return;
}

inline void build(){
	for(re int now=1;now<=n;++now){
		int i=p1[now],j=p2[now];
		if(ma.find(d(i,j))==ma.end())	continue;
		if(i%4==0){
			if(j%2==0){
				red(i,j);
			}
			else{
				yel(i,j);
			}
		}
		else if(i%4==1){
			if(j%2==0){
				yel(i,j);
			}
			else{
				red(i,j);
			}
		}
		else if(i%4==2){
			if(j%2==0){
				gre(i,j);
			}
			else{
				blu(i,j);
			}
		}
		else{
			if(j%2==0){
				blu(i,j);
			}
			else{
				gre(i,j);
			}
		}
	}
	return;
}

inline void BFS(){
	memset(dep,-1,sizeof(dep));
	memset(sum,0,sizeof(sum));
	queue <int> q;
	dep[T]=0,sum[dep[T]]++;
	q.push(T);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(re int y=head[x];y;y=road[y].nex){
			int z=road[y].to;
			if(dep[z]!=-1)	continue;
			dep[z]=dep[x]+1,sum[dep[z]]++;
			q.push(z);
		}
	}
	return;
}

inline int DFS(int x,int flow){
	if(x==T){
		maxflow+=flow;
		return flow;
	}
	int used=0;
	for(re int y=head[x];y;y=road[y].nex){
		int z=road[y].to,w=road[y].w;
		if(w&&dep[z]==dep[x]-1){
			int after=DFS(z,min(w,flow-used));
			if(after){
				used+=after;
				road[y].w-=after;
				road[y^1].w+=after;
			}
		}
		if(flow==used)	return used;
	}
	if(!--sum[dep[x]])	dep[T]=T+1;
	sum[++dep[x]]++;
	return used;
}

inline void ISAP(){
	maxflow=0;
	BFS();
	while(dep[T]<=T)	DFS(S,INF);
	return;
}

inline void print(){
	printf("%lld\n",maxflow);
	return;
}

signed main(){
	scan();
	build();
	ISAP();
	print();
	return 0;
}

T3 P3757 [CQOI2017]老C的键盘

思路:
可以建成一棵二叉树
然后在树上 dp,合并左右子树方案数

代码:

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long

inline int in{
	int s=0,f=1;char x;
	for(x=getchar();x<'0'||x>'9';x=getchar())	if(x=='-')	f=-1;
	for( ;x>='0'&&x<='9';x=getchar())	s=(s*10)+(x&15);
	return f==1?s:-s;
}

const int A=1e3+5;
const int mod=1e9+7;
int n;
char a[A];
int f[A][A],g[A][A],t[A][A],sz[A];
int c[A][A];
int res=0;

inline void DFS(int x){
	sz[x]=1,f[x][1]=1;
	for(int i=2*x;i<=min(n,2*x+1);i++){
		DFS(i);
		sz[x]+=sz[i];
		for(int j=1;j<=sz[x];j++)
			for(int k=0;k<j;k++){
				if(a[i]=='>'){
					t[x][j]=(t[x][j]+c[j-1][k]*c[sz[x]-j][sz[i]-k]%mod*f[i][k]%mod*f[x][j-k])%mod;
				}
				else{
					t[x][j]=(t[x][j]+c[j-1][k]*c[sz[x]-j][sz[i]-k]%mod*g[i][k+1]%mod*f[x][j-k])%mod;
				}
			}
		for(int j=1;j<=sz[x];j++)	f[x][j]=t[x][j],t[x][j]=0;
	}
	for(int i=sz[x];i;i--)	g[x][i]=(g[x][i+1]+f[x][i])%mod;
	for(int i=1;i<=sz[x];i++)	f[x][i]=(f[x][i]+f[x][i-1])%mod;
	return;
}

signed main(){
	n=in;
	scanf("%s",a+2);
	c[0][0]=1;
	for(int i=1;i<=n;i++){
		c[i][0]=1;
		for(int j=1;j<=i;j++)
			c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
	}
	DFS(1);
	printf("%lld\n",f[1][sz[1]]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值