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的更多相关文章

  1. 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)

    [HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...

  2. 结合谷歌地图多边形(polygon)与Sql Server 2008的空间数据类型计算某个点是否在多边形内的注意事项

    首先在利用 GEOGRAPHY::STPolyFromText(@GeoStr, 4326) 这样的函数把字符串转换为Geography类型时,字符串里经纬度的顺序是 “经度[空格]纬度”,即“lon ...

  3. Arcgis api for javascript学习笔记(4.5版本) - 点击多边形(Polygon)并高亮显示

    在现在的 arcgis_js_v45_api 版本中并没有直接提供点击Polygon对象高亮显示.需要实现如下几个步骤: 1.点击地图时,获取Polygon的Graphic对象: 2.对获取到的Gra ...

  4. 百度地图笔记_覆盖物(标注marker,折线polyline,多边形polygon)的点击弹窗和右键菜单

    利用绘制工具绘制点线面,并在执行绘制完成回调事件给相应覆盖物添加事件操作,提供标注的点击弹窗和标注.折线.多边形的右键删除 效果图如下: 完整代码如下:html+js <!DOCTYPE htm ...

  5. [RGEOS]绘制多边形Polygon

    绘制OGIS定义的Polygon public void DrawPolygon(Polygon pol, Brush brush, Pen pen, bool clip) { gc = Graphi ...

  6. luogu P5288 [HNOI2019]多边形

    传送门 这是什么神仙操作... 首先要注意一些性质.首先每一个\((x,n)\)的边可以把当前多边形分成两半,这两半的操作是独立的.然后对于某一个没有\((x,n)\)的边的多边形,最优操作是唯一的. ...

  7. 【洛谷5288】[HNOI2019] 多边形(二叉树模型)

    点此看题面 大致题意: 给你一个多边形,用若干不重合.不相交的线段将其划分为若干三角形区域,并定义旋转操作\((a,c)\)为选定\(4\)个点\(a,b,c,d\)满足\(a<b<c&l ...

  8. css create 多边形 polygon

    案例:   代码: element.style { width: 0; height: 0; /* border-left: 50px solid transparent; */ border-rig ...

  9. [HNOI2019]多边形[二叉树建模、组合计数]

    题意 题目链接 分析 不难发现终态一定是 \([2,n-2]\) 中的每个点都与 \(n\) 连边. 关于凸多边形的划分问题,可以将它看作一棵二叉树:每个树点可以看做点可以看做边. 本题中看做点来处理 ...

随机推荐

  1. android recovery 升级时间与速度研究

    从android4.4到现在android7.1升级,现在的升级包越来越大,一个system分区大小都分配了2G,整个升级包达到了接近500M, 升级包解压之后1G+,奇怪的是,发现了两个不同批次的板 ...

  2. flask day01

    目标:搭建好一个flask架构,并且可以运行起来,能够访问 ## 一丶配置环境 比较简单,只需要配一个flask pip3 install flask #也可以使用pip install flask ...

  3. Django中ORM介绍和字段及字段参数 Object Relational Mapping(ORM)

    Django中ORM介绍和字段及字段参数   Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简 ...

  4. 【js基础】创建对象的几种常见模式(工厂模式,构造函数模式,原型模式,构造原型组合模式)

    一.工厂模式 缺点:没有解决对象识别的问题 优点:解决了创建多个相似对象的问题 function createPerson(name,age,job){ var o = new Object(); o ...

  5. python常用模块json

    python jons模块 json模块 主要是解决数据格式的转换问题,比如python接收到json对象需要转换为python对象,供python处理,亦或者python数据需要发送到其给其他客户端 ...

  6. 浅谈C#依赖注入

    什么是依赖注入?不管是js中的一些前端框架还是,java,C#,php等中的一些后端开发框架中,都会涉及这个看着逼格略高的词语:依赖注入,越是看着好像很厉害的东西越是会让许多人学习产生恐惧,好像很厉害 ...

  7. sql server 数据导出(入)方法总结

    我们都知道日常在面对数据需求时需要导出数据,比较少量的数据导出我们一般是通过查询后另存即可,当面对数据量比较大的时候我们应该怎么处理?我搜索总结一些几个方法:1.bcp 导出.2.数据库本身自带的导入 ...

  8. win7计划任务报该任务映像己损坏或己篡改

    目录 win7计划任务报该任务映像己损坏或己篡改 前言 解决方案 排查损坏的计划任务映像 win7计划任务报该任务映像己损坏或己篡改 文:铁乐与猫 2018-9-20 前言 win7下想自定义一些计划 ...

  9. 16LaTeX学习系列之---LaTeX数学公式的补充

    目录 目录 前言 (一)知识点说明 1.基础细节 2.gather环境 3.align环境 4.split环境 5.cases环境 (二)实例 1.源代码 2.输出效果 目录 本系列是有关LaTeX的 ...

  10. <20180930>故障解决记录Cisco RV系列低端路由

    故障描述: 今日网络瘫痪 , 浏览器提示报 DNS出错, 故障现象: 网关能正常分配到IP但内网机器却无法上网. 其中一个WiFi设备竟然还可以通讯(聊天工具)! 故障思路和排查: 1.1 怀疑是上次 ...