luogu P5288 [HNOI2019]多边形
这是什么神仙操作...
首先要注意一些性质.首先每一个\((x,n)\)的边可以把当前多边形分成两半,这两半的操作是独立的.然后对于某一个没有\((x,n)\)的边的多边形,最优操作是唯一的.拿样例举例,必须先选\((1,5)\),然后多边形被分成两半,这两半分别只能选\((1,3)\),\((3,5)\).
可以发现,这里每次操作的多边形上的点分别是\(l,l+1...,r(l\ge 1,r<n,r-l>1)\)和\(n\),然后最优方案要选\((l,r)\)这条边,把多边形分成\(\{[l,mid],n\}\)和\(\{[mid,r],n\}\)(\(mid\)是当前多边形中的\(l\)和\(r\)除了\(n\)以外的那个公共点)两部分.根据这个我们可以建出若干二叉树,每个点的左右两个儿子是这个多边形操作之后的左右两半多边形(不能是三角形,因为三角形不用操作)
考虑计算答案,第一问答案为这些二叉树节点个数(也就是\(n-1-\)\((x,n)\)边条数),因为每个节点都是一次操作;第二问答案,因为这个二叉树每个节点要在他的父亲之后才能操作,所以如果把每个点看成一个排列中的数,就是要求满足\(x\)在\(fa_x\)后面的排列个数,这个直接把SAO蒯过来就好了对于每个节点的子树,首先这个点要放在第一位,两个儿子子树的序列之间是没有先后关系的,所以一个节点对答案的贡献是\(\binom{sz_{ch_{x,0}}+sz_{ch_{x,1}}}{sz_{ch_{x,0}}}\),把这些贡献乘起来就好了.然后对于所有二叉树的根,我们把他们向一个超级根连边,因为相互没有影响,所以答案还要乘上把所有树合并的方案,类似于树型背包,每次把一个并到总集合,然后类似于上面的组合数即可
现在可能会有一些翻转边的操作.手玩可以发现这相当于对于那条边对应的点进行一次\(rotate\)操作.然后如果这个点不是二叉树的根,那么只要先把这个点和父亲的贡献扣掉,\(rotate\)后在加上新的贡献即可;否则这个点是代表着初始情况最优操作中的一个,第一问答案要减去1,然后第二问答案先要扣掉这个点贡献和这个点子树对超级根的贡献,然后因为这个点被操作了,就相当于删掉这个点,两个儿子分别成为一个新二叉树,那么贡献加上这两个儿子子树并到超级根的贡献就好了
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define uLL unsigned long long
using namespace std;
const int N=1e5+10,mod=1e9+7;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
map<int,int> id[N];
vector<int> e[N];
int fac[N],iac[N];
int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;} return an;}
int inv(int a){return fpow(a,mod-2);}
int C(int n,int m){return m<0||n<m?0:1ll*fac[n]*iac[m]%mod*iac[n-m]%mod;}
int w,n,fa[N],ch[N][2],sz[N],size,rt[N],tp,ans=1;
void bui(int &x,int l,int r)
{
if(l+1==r) return;
x=id[l][r];
sz[x]=1;
int mid=*(--lower_bound(e[l].begin(),e[l].end(),r));
bui(ch[x][0],l,mid),bui(ch[x][1],mid,r);
if(ch[x][0]) fa[ch[x][0]]=x;
if(ch[x][1]) fa[ch[x][1]]=x;
sz[x]+=sz[ch[x][0]]+sz[ch[x][1]];
ans=1ll*ans*C(sz[ch[x][0]]+sz[ch[x][1]],sz[ch[x][0]])%mod;
}
int main()
{
fac[0]=1;
for(int i=1;i<=N-10;++i) fac[i]=1ll*fac[i-1]*i%mod;
iac[N-10]=fpow(fac[N-10],mod-2);
for(int i=N-10;i;--i) iac[i-1]=1ll*iac[i]*i%mod;
w=rd(),n=rd();
for(int i=1;i<n;++i) e[i].push_back(i+1),e[i+1].push_back(i);
e[n].push_back(1),e[1].push_back(n);
for(int i=1;i<=n-3;++i)
{
int x=rd(),y=rd();
e[x].push_back(y),e[y].push_back(x);
id[x][y]=id[y][x]=i;
}
for(int i=1;i<=n;++i) sort(e[i].begin(),e[i].end());
int nn=e[n].size(),ff=n-1-nn;
for(int i=0;i<nn-1;++i)
{
int x=e[n][i],y=e[n][i+1];
if(x+1==y) continue;
++tp,bui(rt[tp],x,y);
}
for(int i=1;i<=tp;++i)
size+=sz[rt[i]],ans=1ll*ans*C(size,sz[rt[i]])%mod;
printf("%d ",ff);
if(w) printf("%d",ans);
puts("");
int q=rd();
while(q--)
{
int x=id[rd()][rd()],na=ans;
if(fa[x])
{
int yy=ch[fa[x]][1]==x;
na=1ll*na*inv(C(sz[ch[x][0]]+sz[ch[x][1]],sz[ch[x][0]]))%mod*inv(C(sz[ch[fa[x]][0]]+sz[ch[fa[x]][1]],sz[ch[fa[x]][0]]))%mod;
na=1ll*na*C(sz[ch[x][yy^1]]+sz[ch[fa[x]][yy^1]],sz[ch[x][yy^1]])%mod*C(sz[ch[x][yy]]+sz[ch[x][yy^1]]+sz[ch[fa[x]][yy^1]]+1,sz[ch[x][yy]])%mod;
}
else
{
na=1ll*na*inv(C(sz[ch[x][0]]+sz[ch[x][1]],sz[ch[x][0]]))%mod*inv(C(size,sz[x]))%mod;
na=1ll*na*C(size-sz[x]+sz[ch[x][0]],sz[ch[x][0]])%mod*C(size-1,sz[ch[x][1]])%mod;
}
printf("%d ",ff-(!fa[x]));
if(w) printf("%d",na);
puts("");
}
return 0;
}
luogu P5288 [HNOI2019]多边形的更多相关文章
- 【题解】Luogu P5288 [HNOI2019]多边形
原题传送门 HN的题目就是毒瘤 我们有以下猜想: 1.最后所有的线都连到了n号点上 2.最小步数应该为n-3-已经连到n号点的线段数量 本来有些边\((a_i,n)\)会将整个图分割成很多个区间.对于 ...
- HNOI2019 多边形 polygon
HNOI2019 多边形 polygon https://www.luogu.org/problemnew/show/P5288 这题镪啊... 首先堆结论: 显然终止状态一定是所有边都连向n了 根据 ...
- 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)
[HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...
- 【洛谷5288】[HNOI2019] 多边形(二叉树模型)
点此看题面 大致题意: 给你一个多边形,用若干不重合.不相交的线段将其划分为若干三角形区域,并定义旋转操作\((a,c)\)为选定\(4\)个点\(a,b,c,d\)满足\(a<b<c&l ...
- Luogu P5292 [HNOI2019]校园旅行
非常妙的一道思博题啊,不愧是myy出的题 首先我们考虑一个暴力DP,直接开一个数组\(f_{i,j}\)表示\(i\to j\)的路径能否构成回文串 考虑直接拿一个队列来转移,队列里存的都是\(f_{ ...
- luogu P5286 [HNOI2019]鱼
传送门 这题真的牛皮,还好考场没去刚( 这题口胡起来真的简单 首先枚举D点,然后对其他所有点按极角排序,同时记录到D的距离.然后按照极角序枚举A,那么鱼尾的两个点的极角范围就是A关于D对称的那个向量, ...
- luogu P5287 [HNOI2019]JOJO
传送门 神™这题暴力能A,这出题人都没造那种我考场就想到的数据,难怪我的垃圾做法有分 先考虑没有撤销操作怎么做,因为每次插入一段一样的字符,所以我们可以把\(x\)个字符\(c\)定义为\(cx\), ...
- luogu P5293 [HNOI2019]白兔之舞
传送门 关于这题答案,因为在所有行,往后跳到任意一行的\(w_{i,j}\)都是一样的,所以可以算出跳\(x\)步的答案然后乘上\(\binom{l}{x}\),也就是枚举跳到了哪些行 如果记跳x步的 ...
- luogu P5294 [HNOI2019]序列
传送门 这个什么鬼证明直接看uoj的题解吧根本不会证明 首先方案一定是若干段等值的\(B\),然后对于一段,\(B\)的值应该是\(A\)的平均值.这个最优方案是可以线性构造的,也就是维护以区间平均值 ...
随机推荐
- spark推测执行的坑
1.spark推测执行开启 设置 spark.speculation=true即可 2.spark开启推测执行的好处 推测执行是指对于一个Stage里面运行慢的Task,会在其他节点的Executor ...
- EF 6.x和EF Core实现返回dynamic类型
前言 未曾想需要直接返回dynamic,多次尝试未能实现,最终还是在stackoverflow上找到了解决方案,特此备忘录. public static dynamic SqlQuery(this D ...
- 关于mysql中unique的插入Duplicate key
MySQL数据库中 如果在后台中不做判断是否unique的column是否存在的话,直接把数据操作给dao层再传给DB的话,就会报重复的唯一值.如果确实是不希望先取出判断unique的column是否 ...
- Cnario 3.8支持哪些操作系统?
Cnario是基于Windows平台开发的软件,包含Server.Messenger和Player三个组件,支持以下Windows 版本系统: Server/Messenger 支持英文版的以下操作系 ...
- 【学习总结】GirlsInAI ML-diary day-14-function函数
[学习总结]GirlsInAI ML-diary 总 原博github链接-day14 认识函数function 函数相当于一个固定的公式,一个映射.有输入,有输出. 1-python内置函数 max ...
- win10安装ab测试工具
1.先下载 https://www.apachehaus.com/cgi-bin/download.plx 2.存到非中文无空格的目录 3.解压,并打开配置文件:Apache24\conf\httpd ...
- 【转】Spark实现行列转换pivot和unpivot
背景 做过数据清洗ETL工作的都知道,行列转换是一个常见的数据整理需求.在不同的编程语言中有不同的实现方法,比如SQL中使用case+group,或者Power BI的M语言中用拖放组件实现.今天正好 ...
- redis优化
一.配置文件优化 bind 127.0.0.1 //允许连接的ip,如果就本机连接最后127.0.0.1 protected-mode yes //是否开启保护模式.默认开启,如果没有设置bind项的 ...
- vue 点击当前元素添加class 去掉兄弟的class 获取当前点击元素的文字
点击当前标签给其添加class,兄弟标签class删除 然后获取当前点击元素的文字 演示地址: https://xibushijie.github.io/static/addClass.html &l ...
- [SimplePlayer] 8. 音视频同步
音频与视频在播放当中可能会由于种种原因(如:音视频并非在同一时间开始播放,或视频由于解码任务繁重导致输出图像延迟等)导致音频与视频的播放时间出现偏差,这种就是音视频的同步问题,本文会对音视频同步进行讨 ...