jzoj5983. 【北大2019冬令营模拟2019.1.1】多边形 (组合数学)
这其实是道打表题……你看我代码就知道了……
咳咳来点严谨证明好了……
前方高能请注意
首先,正多边形近似于圆,可以看做在圆里内接多边形。圆内接多边形最多只有三个锐角。因为凸多边形的外角和为\(360\)度,如果有大于等于\(4\)个锐角,那么有大于等于\(4\)个外角大于\(90\)度,外角和肯定大于\(360\)度,矛盾(话说我当时只猜想出了结论不知道怎么证明……初中数学全还给老师了→_→)
那么分情况讨论\(k=0,1,2,3\)的情况就好了。顺便注意\(n\)为奇数,所以不可能存在直角的情况
k=3
此时,这个多边形肯定是三角形,所以如果\(m\neq 3\)无解。(因为我证不来所以就当做是显然好了)所以这里可以容斥,用总的三角形个数减去钝角三角形的个数
对于钝角三角形,三个点肯定在直径的同一侧,我们可以枚举两个点,然后第三个点肯定在这两个点在圆上较短的那条圆弧上,且上面任意一个点与这两个点组成的三角形都是钝角
从下图中不难看出,直径一边的点数最多为\(\left\lfloor\frac{n}{2}\right\rfloor+1\)
于是我们可以枚举每一个点然后逆时针枚举第二个点,那么当第二个点每逆时针走一格,第三个点能选的位置也相对应增加一个。而第三个点最多能选的位置是\(\left\lfloor\frac{n}{2}\right\rfloor-1\)(减去位于两端的第一第二个点),那么对于这一个点它能形成的钝角三角形就是\(\sum_{i=1}^{\left\lfloor\frac{n}{2}\right\rfloor-1}i\),用等差数列求和公式求和,然后再乘上\(n\)就是总的钝角三角形个数,用总的三角形个数减去它就是锐角三角形个数了
k=2
首先,如果一个角是锐角,那么与这个点\(i\)相邻的两个点,他们不经过\(i\)的那段圆弧必定小于周长的一半。其次,不难发现如果\(k=2\),那么两个锐角相对应的点必定在多边形上相邻
于是我们可以枚举锐角相对应的点,设为\(A,B\),如果下图所示,剩下的点只有落在紫色区域才能使\(A,B\)都是锐角且不存在第三个锐角(如果\(m>3\)都行,如果\(m=3\)只能在上面那块紫色区域)
于是照例枚举\(A\)并逆时针枚举\(B\),设\(AB\)之间有\(k\)个点(不包括\(A,B\)),即上面那个紫色区域里可选的点有\(k\)个,易知下面那块紫色区域可选的点为\(k+1\)个(可选的点都是在正\(n\)边形上的)。上面那块紫色区域,\(k\)最大为\(\left\lfloor\frac{n}{2}\right\rfloor-1\),于是每一个\(A\)上面那块紫色区域的贡献就是\(\sum_{i=1}^{\left\lfloor\frac{n}{2}\right\rfloor-1}C_{i}^{m-2}=C_{\left\lfloor\frac{n}{2}\right\rfloor}^{m-1}\)。如果\(m\neq 3\)就把下面那一块的贡献也加上去。最后将贡献乘上\(n\)就是每一个点的贡献了
这里顺便说一下形如\(\sum_{i=1}^nC_{i}^m\)的东西怎么求和。把它拆出来,前面加上\(C_{0}^m\)和\(C_{0}^{m+1}\)(这两个都等于\(0\))。于是原式为\(C_0^{m+1}+C_0^m+C_{1}^m+C_2^m+...+C_n^m=C_1^{m+1}+C_1^m+...\),然后不断合并前两项,得到\(C_{n+1}^{m+1}\)
k=1
这种情况很麻烦,我们要保证除了枚举的点其它都不是锐角。可以按下图所示的方案来,枚举锐角\(A\),设\(E,F\)为剩下所有点的两个边界,那么\(EF\)不经过\(A\)的那段圆弧的长必定小于圆周长的一半。我们要保证\(E,F\)所对的两个角不是锐角,设\(C,D\)为与\(E,F\)相邻的第一个点,只有在\(C\)和\(E\),\(F\)和\(D\)都在如图直径的同一侧时,才能保证\(E,F\)都是钝角
于是我们可以枚举\(C,D\),则\(C,D\)必在这条直径的两侧,我们可以枚举\(C,D\)之间的点数\(k\)(不包含\(C,D\)),设\(T=\left\lfloor\frac{n}{2}\right\rfloor+1\)(即直径的一边最多能有的点数),则\(k\)的上界为\(T-4\),对于每一个\(k\),考虑\(C,D\)的放法,共有\(k+1\)种,对于每一种\(C,D\)的放法,因为\(E,F\)之间包含\(E,F\)的点数最多为\(T\),所以当\(E\)逆时针移动时,\(F\)能放的位置也逆时针移动,且每次增加\(1\),当\(E,C\)在正\(n\)边形上相邻时,\(F\)能放的位置为\(T-k-3\),于是\(E,F\)放置的方案数为\(\sum_{i=1}^{T-k-3}i\)(先别用等差数列求和公式化掉)
综上,对于每一个作为锐角的点,可行的方案数为$$Ans=\sum_{k=0}{T-4}C_{k}{m-5}(k+1)\sum_{i=1}^{T-k-3}i$$
然后答案乘上个\(n\)就是总的方案数。顺便从上式看出如果\(m<5\)无解
然而上式的计算是\(O(n)\)的,太慢
考虑变换求和顺序,有$$Ans=\sum_{i=1}{T-3}i\sum_{k=0}{T-i-3}C_{k}^{m-5}(k+1)$$
考虑形如\(\sum_{i=0}^n (i+1)C_i^m\)的东西,有$$\sum_{i=0}^n (i+1)C_im=\sum_{i=0}n\frac{(i+1)!}{(m+1)!(m-i)!}(m+1)$$
则这玩意儿等于\((m+1)\sum_{i=0}^nC_{i+1}^{m+1}\),再按照\(k=2\)那个时候最下面说的化一下,又等于\((m+1)C_{n+2}^{m+2}\)
于是$$\sum_{k=0}{T-i-3}C_{k}{m-5}(k+1)=(m-4)C_{T-i-1}^{m-3}$$
原式变为$$Ans=(m-4)\sum_{i=1}^{T-3}i\times C_{T-i-1}^{m-3}$$
当\(T-i-1<m-3\)时组合数为\(0\),所以可以写成$$Ans=(m-4)\sum_{i=1}^{T-m+2}i\times C_{T-i-1}^{m-3}$$
考虑后面那一坨东西,令\(M=m-3\),展开之后为\(C_{T-2}^M+2C_{T-3}^M+...+(T-M-1)C_M^M\)
我们可以在后面加上一堆\(C_{i}^M(i<M)\)反正都等于\(0\),于是上式可以化为\(C_{T-1}^{M+1}+C_{T-2}^{M+1}+...+C_{M+1}^{M+1}=C_{T}^{M+2}\)
综上\(k=1\)时每一个点的答案为\(Ans=(m-4)C_T^{m-1}\)
k=0
只要用所有的情况减去锐角分别为\(1,2,3\)的情况就好了
//minamoto
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++K]=z[Z],--Z);sr[++K]='\n';
}
const int N=1e6,P=1000109107,inv2=500054554;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
int fac[N+5],inv[N+5];
int n,m,k,res;
inline int calc(R int n){return 1ll*n*(n/2)%P*(n/2-1)%P*inv2%P;}
inline int C(R int n,R int m){if(m>n)return 0;return 1ll*fac[n]*inv[m]%P*inv[n-m]%P;}
void init(){
inv[0]=fac[0]=1;fp(i,1,N)fac[i]=mul(fac[i-1],i);
inv[N]=ksm(fac[N],P-2);fd(i,N-1,1)inv[i]=mul(inv[i+1],i+1);
}
int calc3(){
if(m!=3)return 0;
int res=C(n,3);
res=dec(res,calc(n));
return res;
}
int calc2(){
int res=C(n/2,m-1);
if(m!=3)res=add(res,C(n/2+1,m-1));
res=mul(res,n);
return res;
}
int calc1(){
if(m<5)return 0;
int res=0,T=n/2+1;
res=C(T,m-1);
res=mul(res,m-4);
return mul(res,n);
}
int main(){
// freopen("testdata.in","r",stdin);
freopen("polygon.in","r",stdin);
freopen("polygon.out","w",stdout);
int T=read();init();
while(T--){
n=read(),m=read(),k=read();
switch(k){
case 3:res=calc3();break;
case 2:res=calc2();break;
case 1:res=calc1();break;
case 0:{
res=C(n,m);
res=dec(res,calc1()),res=dec(res,calc2()),res=dec(res,calc3());
break;
}
default:res=0;break;
}print(res);
}return Ot(),0;
}
jzoj5983. 【北大2019冬令营模拟2019.1.1】多边形 (组合数学)的更多相关文章
- jzoj5990. 【北大2019冬令营模拟2019.1.6】Bear (状压dp)
题面 题解 我永远讨厌dp.jpg 搞了一个下午优化复杂度最后发现只要有一个小trick就可以A了→_→.全场都插头dp就我一个状压跑得贼慢-- 不难发现我们可以状压,对于每一行,用状态\(S\)表示 ...
- jzoj5991. 【北大2019冬令营模拟2019.1.6】Juice
题面 题解 好迷-- //minamoto #include<bits/stdc++.h> #define R register #define ll long long #define ...
- jzoj5989. 【北大2019冬令营模拟2019.1.6】Forest (set)
题面 题解 为了一点小细节卡了一个下午--我都怕我瞎用set把电脑搞炸-- 观察一次\(1\)操作会造成什么影响,比如说把\(A[i]\)从\(x\)改成\(y\): \(D[x]\)会\(-1\), ...
- jzoj5984. 【北大2019冬令营模拟2019.1.1】仙人掌 (分块)
题面 题解 数据结构做傻了.jpg 考虑每一个节点,它的儿子的取值最多只有\(O(\sqrt {m})\)种,那么可以用一个双向链表维护儿子的所有取值以及该取值的个数,那么对儿子节点修改一个值就是\( ...
- JZOJ[5971]【北大2019冬令营模拟12.1】 party(1s,256MB)
题目 题目大意 给你一棵树,在树上的某一些节点上面有人,要用最小的步数和,使得这些人靠在一起.所谓靠在一起,即是任意两个人之间的路径上没有空的节点(也就是连在一起). N≤200N \leq 200N ...
- [JZOJ5977] 【清华2019冬令营模拟12.15】堆
题目 其中n,q≤500000n,q\leq 500000n,q≤500000 题目大意 让你维护一个堆.支持一下操作: 在某个点的下面加上另一个点,然后进行上浮操作. 询问某一点的权值. 思考历程 ...
- Visual Studio 2019 发布活动 - 2019 年 4 月 2 日
Visual Studio 2019 发布活动 2019 年 4 月 2 日,星期二 | 上午 9:00 (PT) 围观: https://visualstudio.microsoft.com/zh- ...
- [2018冬令营模拟测试赛(二十一)]Problem A: Decalcomania
[2018冬令营模拟测试赛(二十一)]Problem A: Decalcomania 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见&quo ...
- jzoj6101. 【GDOI2019模拟2019.4.2】Path
题目链接:https://jzoj.net/senior/#main/show/6101 记\(f_i\)为从\(i\)号点走到\(n\)号点所花天数的期望 那么根据\(m\)条边等可能的出现一条和一 ...
随机推荐
- [iOS] 初探 iOS8 中的 Size Class
本文转载至 http://www.itnose.net/detail/6112176.html 以前和安卓的同学聊天的时候,谈到适配一直是一个非常开心的话题,看到他们被各种屏幕适配折磨的欲仙欲死 ...
- MongoDB——mongo-connector同步到ES
1.搭建完毕MongoDb复制集环境 2.开始安装 mongo-connector pip install mongo-connector:基于pip命令,不管是linux .window 系统默认有 ...
- Grid++Report设置显示固定行数
一.要实现的功能打印的报表显示固定的行数,并且设置字段的文字可以自动换行二.设置步骤1.鼠标左键单击“明细网格”栏,在右侧属性窗口中设置“追加空白行”属性值为:是:“追加空白行在后”属性值为:是.2. ...
- Git检出远程库的分支等相关操作
来到公司,询问同事后发现系统已经上传到Git远程仓库: 我这里先把远程仓库clone下来: $ git clone http://git.eas****tect.git 发现目录下只有一个READY. ...
- Cocos2d-x如何添加新场景及切换新场景(包括场景特效)
做了一天多的工作终于把此功能搞定了,实际上添加新场景花费不了多少时间,时间主要花在切换到另一个场景的实现上,主要原因是编译时出现了一个错误,百思不得其解,后来经过查资料不断摸索才知道自己问题的所在,改 ...
- linux vsftpd
FTP是CS架构的.使用的是ftp协议. root@ubuntu:/# apt install vsftpd root@ubuntu:/# service vsftpd status ● vsftpd ...
- LightOJ1220 —— 质因数分解
题目链接:https://vjudge.net/problem/LightOJ-1220 1220 - Mysterious Bacteria PDF (English) Statistics ...
- valid No such filter: 'drawtext'"
libfreetype is missing. You'll have to rebuild FFmpeg with this library or disable overlays. --enabl ...
- android实现文字渐变效果和歌词进度的效果
要用TextView使用渐变色,那我们就必须要了解LinearGradient(线性渐变)的用法. LinearGradient的参数解释 LinearGradient也称作线性渲染,LinearGr ...
- 基于官方驱动封装mongodb
还是一如既往先把结构图放出来,上上个版本添加了redis的缓存,但是不满足我的需求,因为公司有项目要求是分布式所以呢,这里我就增加了mongoDb进行缓存分布式,好了先看结构图(1). 总的来说比较蛋 ...