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. 动态导入模块:__import__、importlib、动态导入的使用场景

    相关内容: __import__ importlib 动态导入的使用场景 首发时间:2018-02-23 16:06 __import__: 功能: 是一个函数,可以在需要的时候动态导入模块 使用: ...

  2. 利用朴素贝叶斯分类算法对搜狐新闻进行分类(python)

    数据来源  https://www.sogou.com/labs/resource/cs.php介绍:来自搜狐新闻2012年6月—7月期间国内,国际,体育,社会,娱乐等18个频道的新闻数据,提供URL ...

  3. aws linux主机root帐号登录

    默认情况下,aws主机必须使用pem密码文件并且以ec2-user用户登录系统,之后很多操作都必须用sudo来以root权限执行操作,显得比较麻烦. 以下来自知乎的一个问答,亲测ok ## AWS E ...

  4. 洗礼灵魂,修炼python(56)--爬虫篇—知识补充—编码之url编码

    其实在最前面的某一篇博文里,是绝对提过编码的,有ASCII,有UTF-8,有GB2312等等,这些我绝对说过的. url编码 首先,Http协议中参数的传输是"key=value" ...

  5. python写一个双色球彩票计算器

    首先声明,赌博一定不是什么好事,也完全没有意义,不要指望用彩票发财.之所以写这个,其实是用来练手的,可以参考这个来预测一些其他的东西,意在抛砖引玉. 啰嗦完了,马上开始,先上伪代码 打开网址 读取内容 ...

  6. cc1plus.exe: error: unrecognized command line option "-fno-keep-inline-dllexport "

    在Windows环境下的控制台上,通过qmake指令编译Qt程序时,出现 cc1plus.exe: error: unrecognized command line option "-fno ...

  7. 用python写个简单的小程序,编译成exe跑在win10上

    每天的工作其实很无聊,早知道应该去IT公司闯荡的.最近的工作内容是每逢一个整点,从早7点到晚11点,去查一次客流数据,整理到表格中,上交给素未蒙面的上线,由他呈交领导查阅. 人的精力毕竟是有限的,所以 ...

  8. 【19】Linux系统知识点

    一.积跬步以致千里,积怠情以致深渊 二.目录结构

  9. 全文索引搜索whoosh

    问题 Whoosh是python中解决索引查找的模块,在讨论索引查找的文章已经对有关索引查找进行了阐述,此处具体说明Whoosh模块的应用. 思路说明 Whoosh的安装 这里有具体内容(链接被被阉割 ...

  10. 如何正確的使用 Runtime.exec()

    或許大部分有寫過Java程式的人都知道java.lang.Runtime這個class有一個method叫做exec(),可以被用來呼叫(調用)外部的程式.然而大部分的人都不知道這個method存在著 ...