zoukankan      html  css  js  c++  java
  • P7529 [USACO21OPEN] Permutation G

    题面:

    提供一种思路:

    一个很容易的性质就是合法形成的图形最外围一定是一个三角形形成的凸包。

    所以原图凸包不是三角形就输出0

    我们考虑dp,设当前最外围的三角形是由i,j,k三个点形成的三角形。用f[i][j][k]来记录方案数

    此时我们考虑转移,此时我们可以添加点,分两种情况讨论:

    新添加的点在三角形内部,此时可以直接添加若干个内部点且必定满足限制,
    所以我们多记录一维,用f[i][j][k][p]表示外围是i,j,k,且内部有p个未添加的点的方案数。

    若添加的点在外部,那么此时新添加的点p必定是能连向i,j,k的,如果我们换掉的点是i,新形成的三角形是p,j,k围成的三角形,容易发现p,j,k一定能包住i(i在p,j,k的三角形内部)。此时我们用向量法判断即可:

    有很多种思路,最简单的是判断SΔpij+SΔijk+SΔpik是否等于SΔpjk(用图形的概念去理解)

    然后就转换成了求三角形面积,向量叉积可以判定两向量(三点)形成的平行四边形的面积,然后除以2即可。

    我们就得到了转移

    我们认为转移后的三角形内部的点有A个,原三角形的内部点有B个。

    我们每次转移就相当于从原三角形然后新添加个外围的点然后再加上x(x>=0)个新三角形的点。

    然后用排列组合可知j
    (f表示新三角形即f[i][j][k],下文的f[p]即f[i][j][k][p],F表示原三角形即F[I][J][K],且满足I,J,K能向i,j,k转移,且有两个顶点相同相同,P为排列数)
    f_p=sum_{i+A-B+1>=p}^{i}F[i+A-B+1]*P(i+A-B+1,i+A-B+1-p)

    看起来很长,其实理解一下即可。

    然后我们想转移顺序,发现这其实是个DAG(因为不可能有两个三角形互相包含)

    然后利用拓扑排序转移即可。

    不难发现把P(n,m)转换成n(n-1)(n-2)(n-3)……(n-m+1)就可以利用前缀和实现O(n)转移

    总时间复杂度为O((n^5))(大概,其实跑不满)

    代码:

    
    #include<bits/stdc++.h>
    #define int long long
    
    using namespace std;
    const long long mo=1000000007;
    const double eps=0.0000001;
    int x[45],y[45];
    int n;
    long long f[45][45][45][45];
    int nb[45][45][45];
    int d[45][45][45];
    int cross(int x,int y,int X,int Y){
    	return x*Y-y*X;
    }
    struct zt{
    	int u,v,w;
    };
    bool pd(int i,int j,int k,int p){
    	return (abs(abs(cross(x[k]-x[i],y[k]-y[i],x[j]-x[i],y[j]-y[i]))-(abs(cross(x[j]-x[i],y[j]-y[i],x[p]-x[i],y[p]-y[i]))+abs(cross(x[k]-x[i],y[k]-y[i],x[p]-x[i],y[p]-y[i]))+abs(cross(x[k]-x[j],y[k]-y[j],x[p]-x[j],y[p]-y[j]))))<=eps);
    }
    void zy(int a,int b,int c,int A,int B,int C){
    	long long sum=0;
    	int delta=nb[A][B][C]-nb[a][b][c];
    	for(int j=nb[A][B][C]-1;j>=0;j--){
    		if(j+1>=delta)sum+=f[a][b][c][j-delta+1];
    		sum%=mo;
    		f[A][B][C][j]+=sum;
    		f[A][B][C][j]%=mo;
    		sum*=j;
    		sum%=mo;
    	}
    }
    signed main(){
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++)scanf("%lld%lld",&x[i],&y[i]);
    	bool PD=false;
    	queue<zt>q;
        while(!q.empty())q.pop();
    	int au,av,aw;
    	for(int i=1;i<=n;i++)
    		for(int j=i+1;j<=n;j++)
    			for(int k=j+1;k<=n;k++){
    				for(int p=1;p<=n;p++){
    					if(p==i||p==j||p==k)continue;
    					if(pd(i,j,k,p))nb[i][j][k]++;
    				}
    				if(nb[i][j][k]==n-3)PD=true,au=i,av=j,aw=k;
    				d[i][j][k]=nb[i][j][k]*3;
    				if(d[i][j][k]==0)q.push((zt){i,j,k});
    				long long sum=1;
    				for(int p=nb[i][j][k];p>=0;p--){
    					f[i][j][k][p]=sum*6;
    					sum*=p;
    					sum%=mo;
    				}
    			}
    	if(!PD){
    		puts("0");
    		return 0;
    	}
    	while(!q.empty()){
    		zt now=q.front();
    		q.pop();
    		for(int i=1;i<now.u;i++){
    			if(pd(i,now.v,now.w,now.u)){
    				zy(now.u,now.v,now.w,i,now.v,now.w);
    				d[i][now.v][now.w]--;
    				if(d[i][now.v][now.w]==0)q.push((zt){i,now.v,now.w});
    			}
    			if(pd(i,now.u,now.w,now.v)){
    				zy(now.u,now.v,now.w,i,now.u,now.w);
    				d[i][now.u][now.w]--;
    				if(d[i][now.u][now.w]==0)q.push((zt){i,now.u,now.w});
    			}
    			if(pd(i,now.u,now.v,now.w)){
    				zy(now.u,now.v,now.w,i,now.u,now.v);
    				d[i][now.u][now.v]--;
    				if(d[i][now.u][now.v]==0)q.push((zt){i,now.u,now.v});
    			}
    		}
    		for(int i=now.u+1;i<now.v;i++){
    			if(pd(i,now.v,now.w,now.u)){
    				zy(now.u,now.v,now.w,i,now.v,now.w);
    				d[i][now.v][now.w]--;
    				if(d[i][now.v][now.w]==0)q.push((zt){i,now.v,now.w});
    			}
    			if(pd(now.u,i,now.w,now.v)){
    				zy(now.u,now.v,now.w,now.u,i,now.w);
    				d[now.u][i][now.w]--;
    				if(d[now.u][i][now.w]==0)q.push((zt){now.u,i,now.w});
    			}
    			if(pd(now.u,i,now.v,now.w)){
    				zy(now.u,now.v,now.w,now.u,i,now.v);
    				d[now.u][i][now.v]--;
    				if(d[now.u][i][now.v]==0)q.push((zt){now.u,i,now.v});
    			}
    		}
    		for(int i=now.v+1;i<now.w;i++){
    			if(pd(now.v,i,now.w,now.u)){
    				zy(now.u,now.v,now.w,now.v,i,now.w);
    				d[now.v][i][now.w]--;
    				if(d[now.v][i][now.w]==0)q.push((zt){now.v,i,now.w});
    			}
    			if(pd(now.u,i,now.w,now.v)){
    				zy(now.u,now.v,now.w,now.u,i,now.w);
    				d[now.u][i][now.w]--;
    				if(d[now.u][i][now.w]==0)q.push((zt){now.u,i,now.w});
    			}
    			if(pd(now.u,now.v,i,now.w)){
    				zy(now.u,now.v,now.w,now.u,now.v,i);
    				d[now.u][now.v][i]--;
    				if(d[now.u][now.v][i]==0)q.push((zt){now.u,now.v,i});
    			}
    		}
    		for(int i=now.w+1;i<=n;i++){
    			if(pd(now.v,now.w,i,now.u)){
    				zy(now.u,now.v,now.w,now.v,now.w,i);
    				d[now.v][now.w][i]--;
    				if(d[now.v][now.w][i]==0)q.push((zt){now.v,now.w,i});
    			}
    			if(pd(now.u,now.w,i,now.v)){
    				zy(now.u,now.v,now.w,now.u,now.w,i);
    				d[now.u][now.w][i]--;
    				if(d[now.u][now.w][i]==0)q.push((zt){now.u,now.w,i});
    			}
    			if(pd(now.u,now.v,i,now.w)){
    				zy(now.u,now.v,now.w,now.u,now.v,i);
    				d[now.u][now.v][i]--;
    				if(d[now.u][now.v][i]==0)q.push((zt){now.u,now.v,i});
    			}
    		}
    	}
    	printf("%lld
    ",f[au][av][aw][0]);
    	return 0;
    }
    
    
  • 相关阅读:
    linux上mysql安装详细教程
    druid部署
    druid.io本地集群搭建 / 扩展集群搭建
    CentOS7.1.x+Druid 0.12 集群配置
    Python小项目四:实现简单的web服务器
    hadoop学习---运行第一个hadoop实例
    Hadoop集群完全分布式坏境搭建
    mysql备份与恢复
    mysql登录的三种方式
    nginx代理,负载均衡
  • 原文地址:https://www.cnblogs.com/Kiana-Kaslana/p/15541097.html
Copyright © 2011-2022 走看看