HNOI 2019 多边形
HNOI 2019 多边形
题意
小 R 与小 W 在玩游戏。
他们有一个边数为\(n\)的凸多边形,其顶点沿逆时针方向标号依次为\(1,2,3...n\)。最开始凸多边形中有\(n\)条线段,即多边形的\(n\)条边。这里我们用一个有序数对 \((a,b)\)(其中\(a<b\))来表示一条端点分别为顶点\(a,b\)的线段。
在游戏开始之前,小 W 会进行一些操作。每次操作时,他会选中多边形的两个互异顶点,给它们之间连一条线段,并且所连的线段不会与已存的线段重合、相交(只拥有一个公共端点不算作相交)。他会不断重复这个过程,直到无法继续连线,这样得到了状态\(S_0\)。
小 W 定义了一种「旋转」操作:对于当前状态,选定\(1\le a<b<c<d\le n\)共\(4\)个顶点 ,它们两两之间共有\(5\)条线段—— \((a,b),(b,c),(c,d),(a,d),(a,c)\),然后删去线段\((a,c)\),并连上线段\((b,d)\) 。那么用有序数对\((a,b)\)即可唯一表示该次「旋转」。我们称这次旋转为\((a,c)\)「旋转」。显然每次进行完“旋转”操作后多边形中依然不存在相交的线段。
当小 W 将一个状态作为游戏初始状态展示给小 R 后,游戏开始。游戏过程中,小 R 每次可以对当前的状态进行「旋转」。在进行有限次「旋转」之后,小 R 一定会得到一个状态,此时无法继续进行「旋转」操作,游戏结束。那么将每一次「旋转」所对应的有序数对按操作顺序写下,得到的序列即为该轮游戏的操作方案。
为了加大难度,小W以\(S_0\)为基础,产生了\(m\)个新状态。其中第\(i\)个状态 为对\(S_0\)进行一次「旋转」操作后得到的状态。你需要帮助小R求出分别以\(S_i\)作为游戏初始状态时,小R完成游戏所用的最少「旋转」次数,并根据小W的心情,有时还需求出旋转次数最少的不同操作方案数。由于方案数可能很大,输出时请对\(10^9+7\)取模。
思路
不难发现,边的变化具有方向性,即一条边总是往标号变大的方向变化。
那么,就可以猜测,最终状态为从\(n\)出发的\(n-3\)条线段。
仔细思索,不难证明这个结论是正确的。
再观察样例,猜测最小步数为不与\(n\)相连的边的数目。
这个结论好像也是对的。
所以每次操作必须把一个与\(n\)不相连的边变为与\(n\)相连的边。
由于必须保证不相交,所以这些边的操作有些先后顺序。
他形成了一颗二叉森林的结构。
只考虑一颗树,他的方案数是多少?
\]
它的组合意义是,枚举每个\(x\)的左子树和右子树的次序。
如果把所有树都考虑进去,只需要再枚举一下树之间的次序就可以了。
经过长期的摸索,发现进行一次旋转会有这样的改变。

这是改变\(x\)这条边。答案并不会有很大的变动。
以上。
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
const int sz=1e5+7;
const int mod=1e9+7;
int w;
int n,m;
int r[sz];
int ans,tot;
int Ans,Tot;
int u,v,cnt;
int siz[sz];
int ls[sz],rs[sz],f[sz];
int fac[sz],ifac[sz],inv[sz];
map<pii,int>mp;
struct Edge{
int u,v;
}e[sz];
bool cmp1(Edge p1,Edge p2){
if(p1.u!=p2.u) return p1.u<p2.u;
return p1.v>p2.v;
}
bool cmp2(Edge p1,Edge p2){
if(p1.v!=p2.v) return p1.v>p2.v;
return p1.u<p2.u;
}
void init(){
fac[0]=ifac[0]=1;
fac[1]=ifac[1]=inv[1]=1;
for(int i=2;i<sz;i++){
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[i]=1ll*i*fac[i-1]%mod;
ifac[i]=1ll*inv[i]*ifac[i-1]%mod;
}
}
int C(int n,int m){
return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int iC(int n,int m){
return 1ll*ifac[n]*fac[m]%mod*fac[n-m]%mod;
}
void dfs(int x){
siz[x]=1;
if(ls[x]){
dfs(ls[x]);
siz[x]+=siz[ls[x]];
}
if(rs[x]){
dfs(rs[x]);
siz[x]+=siz[rs[x]];
}
ans=1ll*ans*C(siz[ls[x]]+siz[rs[x]],siz[ls[x]])%mod;
}
int main(){
init();
scanf("%d",&w);
scanf("%d",&n);
for(int i=1;i<=n-3;i++){
scanf("%d%d",&u,&v);
if(u>v) swap(u,v);
e[i]=(Edge){u,v};
mp[mkp(u,v)]=i;
}
sort(e+1,e+n-2,cmp1);
for(int i=1;i<=n-3;i++){
int nu=e[i].u,nv=e[i].v;
int lu=e[i-1].u,lv=e[i-1].v;
if(nv==n) { r[mp[mkp(nu,nv)]]=1;continue;}
if(lv==n) continue;
if(nu==lu){
ls[mp[mkp(lu,lv)]]=mp[mkp(nu,nv)];
f[mp[mkp(nu,nv)]]=mp[mkp(lu,lv)];
r[mp[mkp(nu,nv)]]=1;
}
}
sort(e+1,e+n-2,cmp2);
for(int i=1;i<=n-3;i++){
int nu=e[i].u,nv=e[i].v;
int lu=e[i-1].u,lv=e[i-1].v;
if(nv==n) { r[mp[mkp(nu,nv)]]=1; continue; }
if(lv==n) continue;
if(nv==lv){
rs[mp[mkp(lu,lv)]]=mp[mkp(nu,nv)];
f[mp[mkp(nu,nv)]]=mp[mkp(lu,lv)];
r[mp[mkp(nu,nv)]]=1;
}
}
ans=1;
for(int i=1;i<=n-3;i++){
if(r[i]) continue;
dfs(i);
ans=1ll*ans*ifac[siz[i]]%mod;
tot+=siz[i];
}
ans=1ll*ans*fac[tot]%mod;
printf("%d ",tot);
if(w) printf("%d ",ans);
printf("\n");
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
if(u>v) swap(u,v);
int num=mp[mkp(u,v)];
if(!f[num]){
Tot=tot-1;
Ans=ans;
Ans=1ll*Ans*ifac[tot]%mod*fac[Tot]%mod;
Ans=1ll*Ans*fac[siz[num]]%mod*ifac[siz[num]-1]%mod;
printf("%d ",Tot);
if(w) printf("%d ",Ans);
}
else{
Tot=tot;
Ans=ans;
Ans=1ll*Ans*iC(siz[f[num]]-1,siz[num])%mod;
Ans=1ll*Ans*C(siz[f[num]]-1,siz[ls[num]])%mod;
Ans=1ll*Ans*iC(siz[num]-1,siz[ls[num]])%mod;
Ans=1ll*Ans*C(siz[rs[f[num]]]+siz[rs[num]],siz[rs[num]])%mod;
printf("%d ",Tot);
if(w) printf("%d ",Ans);
}
printf("\n");
}
}
HNOI 2019 多边形的更多相关文章
- LOJ#3054. 「HNOI 2019」鱼
LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...
- 「HNOI 2019」白兔之舞
一道清真的数论题 LOJ #3058 Luogu P5293 题解 考虑$ n=1$的时候怎么做 设$ s$为转移的方案数 设答案多项式为$\sum\limits_{i=0}^L (sx)^i\bin ...
- 【HNOI 2019】校园旅行
Problem Description 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你情不自禁的把 ...
- 【HNOI 2019】JOJO
Problem Description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 \(x\) ...
- Solution -「HNOI 2019」「洛谷 P5293」白兔之舞
\(\mathcal{Description}\) Link. 不想概括题意.jpg \(\mathcal{Solution}\) 定义点集 \(S_c=\{(u,v)|v=c\}\):第 ...
- HNOI2019 简要题解
HNOI 2019 简要题解 没想到自己竟也能有机会写下这篇题解呢. LOJ Luogu Day1T1 鱼 枚举\(AD\)两点后发现\(BC\)与\(EF\)相对独立,因此只需要计算合法的\(BC\ ...
- Solution Set - Border Theory
我发现写 Solution Set 就不用写每道题的题意了,岂不美哉? 首先是一些奇妙结论. 定理 1(弱周期定理) 对于字符串 \(S\),若 \(S[:p]\) 和 \(S[:q]\) ...
- jzoj5983. 【北大2019冬令营模拟2019.1.1】多边形 (组合数学)
这其实是道打表题--你看我代码就知道了-- 咳咳来点严谨证明好了-- 前方高能请注意 首先,正多边形近似于圆,可以看做在圆里内接多边形.圆内接多边形最多只有三个锐角.因为凸多边形的外角和为\(360\ ...
- 计算几何板子题【2019牛客国庆集训派对day7——三角形和矩形】【多边形相交的面积】
链接:https://ac.nowcoder.com/acm/contest/1112/J来源:牛客网 题目描述 Bobo 有一个三角形和一个矩形,他想求他们交的面积. 具体地,三角形和矩形由 8 个 ...
随机推荐
- 语音识别(语音转文字)&& 语音合成(文字转语音)
[语音合成API]SpeechSynthesisUtterance是HTML5中新增的API,用于将指定文字合成为对应的语音.也包含一些配置项,指定如何去阅读(语言,音量,音调)等 // 语音播报 s ...
- TortoiseGit可能遇到Permission denied (publickey).
1.检测是不是没设置公钥和私钥 2.公钥有没有添加到git账户里面去 3.检测如下图路径正确不正确
- Eclipse 中安装 CDT 插件编写 C/C++
使用到的软件 1.Eclipse 开发工具 2.MinGW 编译器 一.Eclipse 中安装 CDT 插件 打开 Eclipse 插件市场 搜索 CDT,并找到如下的插件.插件的版本名字可能不太一样 ...
- ADS 下 flash 烧写程序原理及结构
本原理:在 windows 环境下借助 ADS 仿真器将在 SDRAM 中的一段存储区域中的数据写到 Nand flash 存 储空间中.烧写程序在纵向上分三层完成: 第一层: 主烧写函数(完成将在 ...
- [JZOJ5977] 【清华2019冬令营模拟12.15】堆
题目 其中n,q≤500000n,q\leq 500000n,q≤500000 题目大意 让你维护一个堆.支持一下操作: 在某个点的下面加上另一个点,然后进行上浮操作. 询问某一点的权值. 思考历程 ...
- thinkPHP 字段映射功能
thinkPHP的字段映射功能可以让你在表单中隐藏真正的数据表字段,而不用担心放弃自动创建表单对象的功能,假设我们的User表里面有username和email字段,我们需要映射成另外的字段,定义方式 ...
- ssm框架,出现xxx不能加载,或者bean不能加载时的解决方案之一
有可能是你在项目的mapper.xml文件中添加了本项目没有的实体类, 你把日志中找不到的最后一个实体类全项目搜索下,改成本项目可以引用的即可
- 如何在window和mac下查找数据库
1. mac 下终端使用步骤 cd /Applications/xampp/bin ./mysql -u root 2. window CMD命令中执行步骤 D: cd D:/xampp/mysql ...
- EF Code First数据库连接配置
前面几节,使用的都是通过EF Code First创建的新数据库,接下来,将开始使用已存在的数据库. 1.使用配置文件设置数据库连接 App.config 数据库连接字符串的name与Data中Nor ...
- DotNetBar2设置窗体为office风格
帮同事写个桌面工具,刚学着用DotNetBar2.后面面分享学习过程.下面是给窗体设置成office风格的方法.(1)拷贝DotNetBar2的dll文件,添加引用. (2)在需要用office风格的 ...