HNOI2019 多边形 polygon
HNOI2019 多边形 polygon
https://www.luogu.org/problemnew/show/P5288
这题镪啊。。。
首先堆结论:
显然终止状态一定是所有边都连向n了
根据样例及打表猜个结论,每一步一定可以新连一条到n的边,这个结论也很好证
然后可以把多边形分成若干区间,这些区间形成一棵树。具体划分方法很简单,就是用一些现有的点和中间所有边构成的多边形缩成一个区间,这些点要满足:编号连续,和只有编号最小最大的点与n有连边。比如样例中[1,3],[3,5],[1,5]。
左右端点对应编号最小最大的点,然后这些区间可以根据包含关系连成一棵树,而且这棵树除了根都是二叉的。代码可以模拟
然后每一步会新连一条到n的边,对应到区间上,会把当前区间分开成固定的,互不干扰的两个区间。
发现这就是个裸的dp是吧,\(f[l][r]\)表示这个区间的方案数,现在球出了这个dp,第1问就解决了
开始做第二问。第二问做了一个变换,假设是对\(l,t,k,r\)四个点进行\(l,k\)变换(膜lk),而且k!=n,那么由上面知道第一问答案不会变,而且这棵树的局部会这样变化:

变成

分析一波,下面三个叶子都没变,所以变的只是中间乘的组合数。那么照着这个树,爆算一波,答案是原答案乘\((C^{r-t-2}_{k-t-1}C^{r-l-2}_{t-l-1})\cdot (C^{k-l-2}_{t-l-1}C^{r-l-2}_{r-k-1})^{-1}\)
注意一个特殊情况,就是变换的k=n时,第一问答案-1,第二问答案是原答案乘\((C^{ans1}_{k-l-1})^{-1}C^{ans1-1}_{k-l-2}\),可以看成是1号点最后合并的时候最后合并这个点并且少合并1(ans1是原问题的第一问的答案)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define vd void
#define mod 1000000007
il int gi(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
int n,x[100010],y[100010];
int s[100010],m;
std::vector<int>G[100010];
int L[100010],R[100010],ch[100010][2],cnt;
std::vector<int>ch0;
il int build(int l,int r){
if(r-l<2)return 0;
++cnt;L[cnt]=l,R[cnt]=r;
int ret=cnt,t=*--std::lower_bound(G[l].begin(),G[l].end(),r);
ch[ret][0]=build(l,t);
ch[ret][1]=build(t,r);
return ret;
}
int p[100010],ip[100010];
il int C(int n,int m){
if(n<m)return 0;
return 1ll*p[n]*ip[m]%mod*ip[n-m]%mod;
}
il int invC(int n,int m){
if(n<m)return 0;
return 1ll*ip[n]*p[m]%mod*p[n-m]%mod;
}
int f[100010];
il vd dp(int x){
if(!ch[x][0]&&!ch[x][1]){f[x]=1;return;}
if(!ch[x][0]||!ch[x][1]){dp(ch[x][0]|ch[x][1]);f[x]=f[ch[x][0]|ch[x][1]];return;}
dp(ch[x][0]),dp(ch[x][1]);
f[x]=1ll*f[ch[x][0]]*f[ch[x][1]]%mod*C(R[x]-L[x]-2,R[ch[x][0]]-L[ch[x][0]]-1)%mod;
}
int main(){
// freopen("polygon.in","r",stdin);
// freopen("polygon.out","w",stdout);
int W=gi();
n=gi();
int ans1=n-3;
for(int i=1;i<n;++i)G[i].push_back(i+1);G[1].push_back(n);
for(int i=1;i<=n-3;++i){
x[i]=gi(),y[i]=gi();
if(x[i]>y[i])std::swap(x[i],y[i]);
if(y[i]==n)--ans1,s[++m]=x[i];
G[x[i]].push_back(y[i]);
}
for(int i=1;i<=n;++i)std::sort(G[i].begin(),G[i].end());
int Q=gi();
s[++m]=1,s[++m]=n-1;
std::sort(s+1,s+m+1);
for(int i=1;i<m;++i)ch0.push_back(build(s[i],s[i+1]));
p[0]=1;ip[0]=1;
for(int i=1;i<=n;++i)p[i]=1ll*p[i-1]*i%mod;
ip[1]=1;for(int i=2;i<=n;++i)ip[i]=mod-1ll*ip[mod%i]*(mod/i)%mod;
for(int i=1;i<=n;++i)ip[i]=1ll*ip[i-1]*ip[i]%mod;
int ans=1,siz=0;
for(auto i:ch0)if(i)dp(i),ans=1ll*ans*C(siz+R[i]-L[i]-1,siz)%mod*f[i]%mod,siz+=R[i]-L[i]-1;
if(W)printf("%d %d\n",ans1,ans);
else printf("%d\n",ans1);
while(Q--){
int l=gi(),r,k=gi(),t;if(l>k)std::swap(l,k);
r=*std::upper_bound(G[l].begin(),G[l].end(),k);
t=*--std::lower_bound(G[l].begin(),G[l].end(),k);
if(r==n){
if(W)printf("%d %d\n",ans1-1,1ll*ans*invC(ans1,k-l-1)%mod*C(ans1-1,k-l-2)%mod);
else printf("%d\n",ans1-1);
continue;
}
if(W)printf("%d %d\n",ans1-(r==n),1ll*ans*invC(k-l-2,t-l-1)%mod*invC(r-l-2,r-k-1)%mod*C(r-t-2,k-t-1)%mod*C(r-l-2,t-l-1)%mod);
else printf("%d\n",ans1-(r==n));
}
return 0;
}
HNOI2019 多边形 polygon的更多相关文章
- 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)
[HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...
- 结合谷歌地图多边形(polygon)与Sql Server 2008的空间数据类型计算某个点是否在多边形内的注意事项
首先在利用 GEOGRAPHY::STPolyFromText(@GeoStr, 4326) 这样的函数把字符串转换为Geography类型时,字符串里经纬度的顺序是 “经度[空格]纬度”,即“lon ...
- Arcgis api for javascript学习笔记(4.5版本) - 点击多边形(Polygon)并高亮显示
在现在的 arcgis_js_v45_api 版本中并没有直接提供点击Polygon对象高亮显示.需要实现如下几个步骤: 1.点击地图时,获取Polygon的Graphic对象: 2.对获取到的Gra ...
- 百度地图笔记_覆盖物(标注marker,折线polyline,多边形polygon)的点击弹窗和右键菜单
利用绘制工具绘制点线面,并在执行绘制完成回调事件给相应覆盖物添加事件操作,提供标注的点击弹窗和标注.折线.多边形的右键删除 效果图如下: 完整代码如下:html+js <!DOCTYPE htm ...
- [RGEOS]绘制多边形Polygon
绘制OGIS定义的Polygon public void DrawPolygon(Polygon pol, Brush brush, Pen pen, bool clip) { gc = Graphi ...
- luogu P5288 [HNOI2019]多边形
传送门 这是什么神仙操作... 首先要注意一些性质.首先每一个\((x,n)\)的边可以把当前多边形分成两半,这两半的操作是独立的.然后对于某一个没有\((x,n)\)的边的多边形,最优操作是唯一的. ...
- 【洛谷5288】[HNOI2019] 多边形(二叉树模型)
点此看题面 大致题意: 给你一个多边形,用若干不重合.不相交的线段将其划分为若干三角形区域,并定义旋转操作\((a,c)\)为选定\(4\)个点\(a,b,c,d\)满足\(a<b<c&l ...
- css create 多边形 polygon
案例: 代码: element.style { width: 0; height: 0; /* border-left: 50px solid transparent; */ border-rig ...
- [HNOI2019]多边形[二叉树建模、组合计数]
题意 题目链接 分析 不难发现终态一定是 \([2,n-2]\) 中的每个点都与 \(n\) 连边. 关于凸多边形的划分问题,可以将它看作一棵二叉树:每个树点可以看做点可以看做边. 本题中看做点来处理 ...
随机推荐
- JavaScript大杂烩12 - 理解Ajax
AJAX缘由 再次谈起这个话题,我深深的记得就在前几年,AJAX被炒的如火如荼,就好像不懂AJAX,就不会Web开发一样.要理解AJAX为什么会出现,就要先了解Web开发面临的问题. 我们先来回忆一下 ...
- [20170628]完善ooerr脚本.txt
[20170628]完善ooerr脚本.txt --//注意不是oracle的oerr,是我写的一个小脚本,下面会提到.很简单.^_^.--//参考链接:blog.itpub.net/267265/v ...
- C# RSA 加密
class Sign_verifySign { #region prepare string to sign. //example format: a=123&b=xxx&c (wit ...
- CentOS7:搭建配置SVN服务器
1. 安装 CentOS通过yum安装subversion. $ sudo yum install subversion subversion安装在/bin目录: $ which svnserve / ...
- JQuery实现1024小游戏
最近用Jqery写了一个1024小游戏,由于是第一次写小游戏,所以就选了一个基础的没什么难度游戏.具体实现如下: 首先在开发时将整个游戏分成两层(自认为),底层是游戏的数据结构以及对数据的操作,上层是 ...
- 拓普微智能TFT液晶显示模块
关键词: 串口屏, 液晶屏, TFT,人机界面 概述: 智能模块(Smart LCD)是专为工业显示应用而设计的TFT液晶显示模块. 模块自带主控IC.Flash存储器.实时嵌入式操作系统,客户主机可 ...
- CRM项目之stark组件(2)
那么从今天开始呢,我们就要开始设计属于我们自己的admin组件,起个名字就叫stark吧(当然你愿意叫什么都可以). stark组件之四步走 仿照admin组件实现流程,stark组件要实现四件事情: ...
- 免费代理IP地址列表
代理地址最后验证日期:2017-8-28 纯真 66免费代理网 #推荐 西刺免费代理IP 酷伯伯HTTP代理 快代理 proxy360.cn 站大爷 Free Proxy List 年少#不稳定 全网 ...
- RelativeLayout 总结
1)参考元素获取:id: 2)位置关系设置: 3)对齐关系设置:
- 函数中声明变量不用Var的情况
我们都知道函数中声明变量不用Var时这个变量会成为全局变量,但是并不是函数一开始执行就会把它变为全局变量,必须执行到这条语句. 看一段代码 function f(){ alert(a); ...