• 【FCS NOI2018】福建省冬摸鱼笔记 day3


    第三天。

    计算几何,讲师:叶芃(péng)。

    dalao们日常不记笔记。@ghostfly233说他都知道了,就盼着自适应辛普森积分。

    我计算几何基础不好……然而还是没怎么讲实现,感觉没听什么东西进去。

    不过还是记了一些公式。

    同时@ghostfly233在后面打农药。

    然后讲到了有关圆的东西。讲完了,下课了。辛普森有兴趣的同学回去自己看看吧。

    辛普森:???

    @ghostfly233非常难受。


    中午划水。


    下午有一题和早上的有关。

    T1半平面交+面积,简单题,我半平面交写错了,只有80。

    T2神秘图论结论+神秘数学/神秘DP,那个结论第一天就接触过了,然而我不知道放那儿有啥用,于是不会做,其实再证一个结论就简单状压DP了。

    T3毒瘤分治啥的,没想法,搞了个最坏(O(n^2))的RMQ,结果70分???@qrc和我差不多,只有30分,因为他预处理(O(n^2)),233333。数据出水了。

    150分比较舒服。

    【T1】

    题面:求一个凸包内部,随机取点P,使得P与给定一边组成的三角形,比P与其他边组成的三角形面积都要小,取到这样的点P的概率。

    题解:一看就是半平面交再算面积,算出给定边和其他边的那条直线(使得P在直线一侧,三角形更小),交一交就好了。

    难点在于如何求出直线,其实推推式子就没问题,第二个是半平面交,我写挂了,幸好不是什么严重错误,于是80分。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define db double
    using namespace std;
    const db eps=1e-10;
    struct vec{db x,y;vec(db x=0,db y=0):x(x),y(y){}};
    inline vec operator+(vec x,vec y){return vec(x.x+y.x,x.y+y.y);}
    inline vec operator-(vec x,vec y){return vec(x.x-y.x,x.y-y.y);}
    inline vec operator*(db  x,vec y){return vec(x*y.x,x*y.y);}
    inline vec operator*(vec x,db  y){return vec(y*x.x,y*x.y);}
    inline db operator *(vec x,vec y){return x.x*y.y-x.y*y.x;}
    inline db mod(vec x){return sqrt(x.x*x.x+x.y*x.y);}
    inline bool zero(db x){if(x<=eps&x>=-eps)return 1;return 0;}
    struct line{vec p,v;line(vec p=vec(0,0),vec v=vec(0,0)):p(p),v(v){}};
    inline bool cmp(line x,line y){return atan2(x.v.y,-x.v.x)<atan2(y.v.y,-y.v.x);}
    void print(vec x){printf("(%lf, %lf)",x.x,x.y);}
    void print(line x){print(x.p);printf(" -> ");print(x.v);puts("");}
    inline vec jiao(line x,line y){
    	return x.p+((((y.p-x.p)*y.v)/(x.v*y.v))*x.v);
    }
    inline line clac(line x,line y){
    	if(zero(x.v*y.v)) return line(y.p+((x.p-y.p)*(mod(x.v)/(mod(x.v)+mod(y.v)))),x.v-y.v);
    	return line(jiao(x,y),x.v-y.v);
    }
    inline bool left(line x,vec y){
    	return (x.v*(y-x.p))>-eps;
    }
    int n,cnt; db ans1,ans2;
    vec dots[100001];
    line edge[100001];
    line edg2[200001];
    line que[200001];int l=1,r=0;
    int main(){
    	freopen("convex.in","r",stdin);
    	freopen("convex.out","w",stdout);
    /*	while(1){
    		line p1,p2;
    		line v;
    		scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&p1.p.x,&p1.p.y,&p1.v.x,&p1.v.y,&p2.p.x,&p2.p.y,&p2.v.x,&p2.v.y);
    		print(p1); print(p2);
    		v=clac(p1,p2);
    		print(v);
    	}*/
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i) scanf("%lf%lf",&dots[i].x,&dots[i].y);
    //======
    	ans1+=dots[n]*dots[1];
    	for(int i=1;i<n;++i) ans1+=dots[i]*dots[i+1];
    	ans1/=2; ans1=abs(ans1);
    //======
    	for(int i=1;i<n;++i) edge[i]=line(dots[i],dots[i+1]-dots[i]);
    	edge[n]=line(dots[n],dots[1]-dots[n]);
    	edg2[++cnt]=line(dots[1],dots[n]-dots[1]);
    	for(int i=2;i<=n;++i) edg2[++cnt]=line(dots[i],dots[i-1]-dots[i]);
    	for(int i=2;i<=n;++i) edg2[++cnt]=clac(edge[1],edge[i]);
    	sort(edg2+1,edg2+cnt+1,cmp);
    //======
    //	puts("======");
    //	for(int i=1;i<=cnt;++i) print(edg2[i]);
    //	puts("======");
    //======
    	que[++r]=edg2[1]; que[++r]=edg2[2];
    	for(int i=3;i<=cnt;++i){
    //		puts("######");
    //		for(int j=l;j<=r;++j) print(que[j]);
    //		puts("######");
    		while(l<=r-1&&left(edg2[i],jiao(que[r],que[r-1]))) --r;
    		while(l<=r-1&&left(edg2[i],jiao(que[l],que[l+1]))) ++l;
    		if(zero(que[r].v*edg2[i].v)){
    			if(l<=r-1&&left(edg2[i],jiao(que[r],que[r-1]))) --r;
    			else continue;
    		}
    		que[++r]=edg2[i];
    	}
    	while(l<=r-1&&left(edg2[l],jiao(que[r],que[r-1]))) --r;
    //======
    //	puts("======");
    //	for(int i=l;i<=r;++i) print(que[i]);
    //	puts("======");
    //======
    	if(l==r-1) ans2=0;
    	else{
    		ans2+=jiao(que[l],que[l+1])*jiao(que[l],que[r]);
    		ans2+=jiao(que[r],que[l])*jiao(que[r],que[r-1]);
    		for(int i=l+1;i<=r-1;++i) ans2+=jiao(que[i],que[i+1])*jiao(que[i],que[i-1]);
    		ans2/=2; ans2=abs(ans2);
    	}
    //======
    	printf("%.4f",ans2/ans1);
    	return 0;
    }
    

    【T2】

    题意:给定一个二分图G={V=X+Y,E},每个点有价值,求有多少个V的子集S的价值大于等于给定的t,并且S可以被原图G中的一个匹配覆盖。(|X|,|Y|leq 20)

    题解:Hall定理:对于一个二分图G={X+Y,E},那么存在一个能覆盖X的匹配当且仅当对于任意一个X的子集,从它引边到Y后,Y被覆盖的点的数量大于等于这个子集的点的数量。

    那么,还要证明一个结论:对于二分图G={X+Y,E},如果X的子集P能被一个G的匹配MP覆盖,Y的子集Q能被一个G的匹配MQ覆盖,那么G必有一个匹配能覆盖P+Q。

    为什么呢?如果P中的一个点通过MP到达Y的点不在Q中,那这条边就可以选取,因为P没有另一个点通过MP能到达同一个点;反之,如果在Q中,那这个点再通过MQ到达X,重复这个过程,最后会形成一条链或一个环,在链中的话我们隔着取边,不论长度为奇数或偶数都可以取到,如果是一个环,那么必须是一个偶环,因为是二分图,所以我们仍然隔着取边就好了。

    那么我们要做的是:①处理X,Y中的每个子集是否有匹配能覆盖它,②把可以的按照价值排序,③双指针扫一遍。

    ①可以用状压DP解决。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,t,s,num[1048576],A[1048576],B[1048576],vA[1048576],vB[1048576],sA[1048576],sB[1048576],cA,cB;
    bool fA[1048576],fB[1048576];
    long long ans;
    int main(){
    	freopen("match.in","r",stdin);
    	freopen("match.out","w",stdout);
    	scanf("%d%d",&n,&m); s=n>m?n:m;
    	for(int i=1;i<1<<s;++i) num[i]=num[i-(i&-i)]+1;
    	char ch;
    	for(int i=0;i<n;++i) for(int j=0;j<m;++j)
    		ch=getchar(), ch=='1'?A[1<<i]|=1<<j,B[1<<j]|=1<<i:ch!='0'?--j:0;
    	for(int i=0;i<1<<n;++i) A[i]=A[i&-i]|A[i-(i&-i)];
    	for(int i=0;i<1<<m;++i) B[i]=B[i&-i]|B[i-(i&-i)];
    	for(int i=0;i<n;++i) scanf("%d",vA+(1<<i));
    	for(int i=0;i<m;++i) scanf("%d",vB+(1<<i));
    	for(int i=0;i<1<<n;++i) vA[i]=vA[i&-i]+vA[i-(i&-i)];
    	for(int i=0;i<1<<m;++i) vB[i]=vB[i&-i]+vB[i-(i&-i)];
    	for(int i=0;i<1<<n;++i){
    		if(num[A[i]]<num[i]) continue;
    		fA[i]=1;
    		for(int j=0;j<n;++j) if(i>>j&1)
    			fA[i]&=fA[i^1<<j];
    		fA[i]?sA[cA++]=vA[i]:0;
    	} sort(sA,sA+cA);
    	for(int i=0;i<1<<m;++i){
    		if(num[B[i]]<num[i]) continue;
    		fB[i]=1;
    		for(int j=0;j<n;++j) if(i>>j&1)
    			fB[i]&=fB[i^1<<j];
    		fB[i]?sB[cB++]=vB[i]:0;
    	} sort(sB,sB+cB);
    	scanf("%d",&t);
    	for(int i=0,j=cB;i<cA;++i){
    		while(j>0&&sA[i]+sB[j-1]>=t) --j;
    		ans+=cB-j;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    [转]HSPICE软件的应用及常见问题解决
    Node.js基于Express框架搭建一个简单的注册登录Web功能
    Node.js开发Web后台服务
    mysql update 将一个表某字段设为另一个表某字段的值
    一个最简的Thinkphp3.2 操作Mongodb的例子
    MongoDB GUI( Robo 3T) Shell使用及操作
    Robomongo,Mongo可视化工具
    thinkphp mysql和mongodb 完美使用
    大型网站系统架构演化之路
    30个php操作redis常用方法代码例子
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/8456364.html
Copyright © 2020-2023  润新知