雅礼集训2019 Day4

雅礼集训2019 Day4

大爷

第一眼感觉是个线性规划的形式,两棵树一模一样的好像可以贪心

\[\operatorname{maximize} \sum_{i}^{n} x_iw_i\\ \operatorname{s.t.} \left\{ \begin{aligned} \sum_i x_iA_{i,1} = c_1\\ \cdots \\ \sum_i x_iA_{i,2n} = c_{2n} \end{aligned} \right. \\x\geq 0 \\x\leq 1 \]

暴力单纯形肯定不行,想了一下这东西就继承贪心思路+费用流。s->第一棵树->第二棵树->t即可。

具体建模方式:

#include<bits/stdc++.h>
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
using namespace std;
int read(){
	int x=0,pos=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
	return pos?x:-x; 
} 
const int N = 601;
int n,m,rt1,rt2;
const int inf = 1e9+7;
struct node{
	int v,nex,w,c;
};
int val[N];
int s,t,tot;
int mxf,totc;
namespace dinic{
	int head[N*4],cur[N*4];node edge[N*20];int top=1;
	int dis[N*4],vis[N*4];
	void add(int u,int v,int w,int c){
		edge[++top].v=v;edge[top].nex=head[u];head[u]=top;edge[top].w=w;edge[top].c=c;
		edge[++top].v=u;edge[top].nex=head[v];head[v]=top;edge[top].w=0;edge[top].c=-c;
	}
	int bfs(){
		queue<int>q;
		FOR(i,1,tot) dis[i]=inf,vis[i]=0;
		dis[s]=0;q.push(s);
		while(!q.empty()){
			int now=q.front();q.pop();vis[now]=0;
			for(int i=head[now];i;i=edge[i].nex){
				int v=edge[i].v;
				if(edge[i].w&&dis[v]>dis[now]+edge[i].c){
					dis[v]=dis[now]+edge[i].c;
					if(!vis[v]){
						vis[v]=1;q.push(v);
					}
				}
			}
		}
		return dis[t]<inf;
	}
	int dfs(int now,int flow){
		int res=flow;
		if(now==t||flow==0) return flow;
		vis[now]=1;
		for(int &i=cur[now];i;i=edge[i].nex){
			int v=edge[i].v;
			if(!vis[v]&&edge[i].w&&dis[v]==dis[now]+edge[i].c){
				int nw=dfs(v,min(res,edge[i].w));
				edge[i].w-=nw;edge[i^1].w+=nw;totc+=nw*edge[i].c;res-=nw;
				if(!res) return flow;
			}
		}
		vis[now]=0;
		return flow-res;
	}
	void solve(){
		while(bfs()){
			memcpy(cur,head,sizeof cur);
			mxf+=dfs(s,inf);
		}
	}
}
struct T{
	int head[N];node edge[N*2];int top;
	int a[N];int w[N];
	vector<int>par[N];int tpe,flg;
	T(){
		FOR(i,1,N-1) a[i]=inf;
		top=flg=0;tpe=1;
	}
	void add(int u,int v){
		edge[++top].v=v;
		edge[top].nex=head[u];
		head[u]=top;
	}
	void dfs(int now,int pre,int tp){
		par[tp].push_back(now);
		for(int i=head[now];i;i=edge[i].nex){
			int v=edge[i].v;
			if(a[v]==inf) a[v]=0;
			if(v==pre) continue;
			if(a[v]){
				w[tp]-=a[v];
				if(w[tp]<0) return flg=1,void();
				w[++tpe]=a[v];dfs(v,now,tpe);
			}else{
				dfs(v,now,tp);
			}
		}
	}
	void work(){
		FOR(i,1,tpe){
			int li=par[i].size();int vn=++tot;
			dinic::add(s,vn,w[i],0);
			for(int j=0;j<li;j++){
				int v=par[i][j];
				dinic::add(vn,v,1,-val[v]);
			}
		}
	}
	void work2(){
		FOR(i,1,tpe){
			int li=par[i].size();int vn=++tot;
			dinic::add(vn,t,w[i],0);
			for(int j=0;j<li;j++){
				int v=par[i][j];
				dinic::add(v,vn,1,0);
			}
		}
	}
}t1,t2;
int main(){
	freopen("w.in","r",stdin);
	freopen("w.out","w",stdout);
	n=read();rt1=read(),rt2=read();
	FOR(i,1,n) val[i]=read();
	FOR(i,1,n-1){
		int u=read(),v=read();
		t1.add(u,v);t1.add(v,u);
	}
	FOR(i,1,n-1){
		int u=read(),v=read();
		t2.add(u,v);t2.add(v,u);
	}
	int q0=read();
	FOR(i,1,q0){
		int x=read(),y=read();
		t1.a[x]=min(t1.a[x],y);
	}
	int q1=read();
	FOR(i,1,q1){
		int x=read(),y=read();
		t2.a[x]=min(t2.a[x],y);
	}
	s=n+1,t=n+2;tot=n+2;
	t1.w[1]=t1.a[rt1];
	t1.dfs(rt1,0,1);
	if(t1.flg) {
		printf("-1");return 0;
	}
	t1.work();
	t2.w[1]=t2.a[rt2];
	t2.dfs(rt2,0,1);
	if(t2.flg) {
		printf("-1");return 0;
	}
	t2.work2();
	dinic::solve();
	if(mxf==t1.a[rt1]&&mxf==t2.a[rt2]){
		printf("%d",-totc);
	}else{
		printf("-1");
	}
	return 0;
} 

关于数据,我写了个python把subtask从文件夹里提出来好自动添加试题(没有cdf差评)

import os
import sys

inn=0
outn=0

problemname='n'

def getFileList(dir,mylist):
    global inn
    global outn
    global problemname
    for file in os.listdir(dir):
        file_path = os.path.join(dir,file) #绝对路径
        if os.path.isdir(file_path):
            getFileList(file_path,mylist)
        else:
            if(file_path.endswith('.in')):
                inn+=1
                os.system ("xcopy %s %s\%s%d.in /s /y /F" % (file_path, mylist, problemname, inn))
            else:
                if(file_path.endswith('.ans')):
                    outn+=1
                    os.system ("xcopy %s %s\%s%d.out /s /y /F" % (file_path, mylist, problemname, outn))

if __name__ == '__main__':
    mylist='E:\lemon\雅礼集训\DAY4\data\%s' %(problemname)
    getFileList(mylist,mylist)

然而有些问题所以只能半自动。。。(要一直按F)(我不是加了/F吗?没用啊)

熊猫

容斥倒是可以容斥,转化成不能满足某些条件也跟容斥之前差不多...

如果没有大小的限制,直接枚举00的段数,接在一段前面的就是10,接在后面的就是01,剩下的是11,边界情况讨论一下,乘上组合数

那么再枚举一下可以无限制的长度,应该就能做\(len^2\),实现应该会很复杂

也可以构建出自动机,然后就不会了

题解:把枚举改成插板法,讨论略复杂

鸽子

第一次看以为是求任意折线上距离为定值的距离最小值,写了个三分,写完才发现这只是subtask4

正解就是把上面的改一下,把m-1个区间重叠起来,二分答案然后检查有无一个点被覆盖m次即可。具体实现我是二分里先三分再二分,总复杂度\(O(n\log^2n)\)。统计的话覆盖数=左端点-右端点,注意要卡常。

总结:读题重要啊...

#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
using namespace std;
const int N = 50001;
inline int read(){
	int x=0,pos=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
	return pos?x:-x; 
}
#define db double 
struct point{
	db x,y;db dis;
	point(db x=0,db y=0):x(x),y(y){dis=sqrt((x)*(x)+(y)*(y));}
	//db gd(const point &b){
	//	return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));
//	}
	point operator -(point b){
		return point(x-b.x,y-b.y);
	}
	point operator +(point b){
		return point(x+b.x,y+b.y);
	}
	point operator *(db b){
		return point(x*b,y*b);
	}
};
point p[N];
int n,m;
db tot[N];
db di=0;
struct typ{
	point s,t;int id;db dis;
	typ(point s=point(0,0),point t=point(0,0),int id=0,db dis=0):s(s),t(t),id(id),dis(dis){}
}; 
typ v[N*2];
db mn[N*2];
int cmp(const typ &a,const typ &b){
	if(a.id==b.id){
		return a.dis<b.dis; 
	}else return a.id<b.id;
}
db calc(typ a,typ b,db len){
	point si=a.s+(b.s-a.s)*(len/(b.s-a.s).dis);
	point ti=a.t+(b.t-a.t)*(len/(b.t-a.t).dis);
	return (ti-si).dis;
}
#define pdi pair<db,int>
#define fi first
#define mp make_pair
#define se second
pdi vec[N*4];
int tp=0,top=0,re=0;
void add(db l,db r){
	//printf("%f %f\n",l,r);
	int ss=((int)(l/di)),tt=((int)(r/di));
	if(ss==tt){
		l-=di*ss,r-=di*tt;
		vec[++tp]=mp(l,1);
		vec[++tp]=mp(r,-1);
	}else{
		re+=tt-ss-1;
		//printf("%f %f\n",l,r);
		l-=di*ss,r-=di*tt;
		//ori++;
		vec[++tp]=mp(0,1);
		vec[++tp]=mp(r,-1);
		vec[++tp]=mp(l,1);
		vec[++tp]=mp(di,-1);
		//vec[++tp]=mp(di,-1);
		//ed++;
	}
}
db lmi[N*2],lmx[N*2],rmi[N*2],rmx[N*2]; 
db lni[N*2],rni[N*2],cnc[N*2];
void getmn(typ a,typ b,int id){
	if((a.s-b.s).dis<1e-6) return;
	db len=(a.s-b.s).dis;
	db l=0,r=len;
	while(r-l>1e-6){
		db m1=l+(r-l)/3,m2=r-(r-l)/3;
		if(calc(a,b,m1)<calc(a,b,m2)){
			r=m2;
		}else l=m1;
	}
	mn[id]=l;
	lmi[id]=0,lmx[id]=l;
	rmi[id]=l,rmx[id]=len;
	cnc[id]=calc(a,b,l);
}
inline void update1(db lim){
	for(register int i=2;i<=top;++i){
		if(cnc[i]>lim) continue;
		lmi[i]=lni[i],rmx[i]=rni[i];
	}
	if(cnc[1]>lim) return;
		lmi[1]=lni[1],rmx[1]=rni[1];
}
inline void update2(db lim){
	for(register int i=2;i<=top;++i){
		if(cnc[i]>lim) continue;
		lmx[i]=lni[i],rmi[i]=rni[i];
	}
	if(cnc[1]>lim) return;
		lmx[1]=lni[1],rmi[1]=rni[1];
}
void solve(typ a,typ b,db lim,int id){
//	printf("%f %f\n",(a.s-b.s).dis,(a.t-b.t).dis);
	//assert(fabs((a.s-b.s).dis-(a.t-b.t).dis)<1e-6);
	db low=mn[id];
	//db len=(a.s-b.s).dis;
	if(calc(a,b,low)>lim) return;
	db l=lmi[id],r=lmx[id];
		while(r-l>1e-6){
			db mid=(l+r)/2.0;
			if(calc(a,b,mid)>lim) l=mid;
			else r=mid;
		}
		//add(tot[a.id]+a.dis+l,tot[a.id]+a.dis+low);
		lni[id]=l;
	db ln=l; 
		l=rmi[id],r=rmx[id];
		while(r-l>1e-6){
			db mid=(l+r)/2.0;
			if(calc(a,b,mid)>lim) r=mid;
			else l=mid;
		}
		add(tot[a.id]+a.dis+ln,tot[a.id]+a.dis+r);
		rni[id]=r;
}
int cmp1(pdi a,pdi b){
	if(fabs(a.fi-b.fi)>1e-6) return a.fi<b.fi;
	else return a.se<b.se;
}
int check(db mid){
	tp=0;re=0;
	for(register int i=2;i<=top;++i){
		solve(v[i-1],v[i],mid,i);
	}
	solve(v[top],v[1],mid,1); 
	int res=re;
	sort(vec+1,vec+tp+1,cmp1);
	for(int i=1;i<=tp;++i){
		res+=vec[i].se;if(res==m) return 1;
		//printf("%d\n",res);
	}
	return 0;
}
int main(){
	freopen("n.in","r",stdin);
	freopen("n.out","w",stdout);
	n=read();m=read();
	FOR(i,1,n){
		int x=read(),y=read();
		p[i]=point(x,y);
		//p[i].x=read(),p[i].y=read();
	} 
	FOR(i,1,n){
		tot[i]=di;
		di+=(p[i%n+1]-p[i]).dis;
	}
	db w=0;int pos=1;
	db dn=di;di=di/m;
	if(m>n){
		printf("%.10f",di);return 0;
	}
	FOR(i,1,n){
		while(w+(p[pos%n+1]-p[pos]).dis<di) w+=(p[pos%n+1]-p[pos]).dis,pos=pos%n+1;
		point nw=p[pos]+(p[pos%n+1]-p[pos])*((di-w)/((p[pos%n+1]-p[pos]).dis));
		v[++top]=typ(p[i],nw,i,0); 
		w-=(p[i%n+1]-p[i]).dis;
	}
	w=dn,pos=1;
	FOR(i,1,n){
		while(w-(p[pos%n+1]-p[pos]).dis>di) w-=(p[pos%n+1]-p[pos]).dis,pos=pos%n+1;
		point nw=p[pos]+(p[pos%n+1]-p[pos])*((w-di)/((p[pos%n+1]-p[pos]).dis));
		v[++top]=typ(nw,p[i],pos,w-di);
		w+=(p[i%n+1]-p[i]).dis;
	}
	//cout<<clock()<<endl;
	sort(v+1,v+top+1,cmp);
	for(register int i=2;i<=top;++i){
		getmn(v[i-1],v[i],i);
	}
	getmn(v[top],v[1],1); 
	//cout<<clock()<<endl;
	db l=0,r=1e7;
	while(fabs(r-l)>1e-6){
		db mid=(l+r)/2;
		if(check(mid)) r=mid,update1(mid);
		else l=mid,update2(mid);
		//cout<<clock()<<endl;
	}
	printf("%.10f",r);
	return 0;
}
posted @ 2020-06-17 12:06  lcyfrog  阅读(213)  评论(0编辑  收藏  举报