HDU7046 Fall with Trees 完美二叉树的定义: (1)是完全二叉树 (2)对于所有层,上一层和下一层的纵坐标的差都相同 (3)同一层,相邻兄弟的横坐标的差都相同 (4)对于每一个节点,它的横坐标就是它所有儿子的横坐标的平均值
给定根节点和它的左儿子和右儿子的坐标,给定树的深度
k
k
k 求这个完美二叉树的凸包的面积
样例组数
T
<
2
×
1
0
5
T <2\times 10^5
T<2×105
2
≤
k
≤
1
0
4
2\le k\le 10^4
2≤k≤104
思路
把凸包面积拆成一个三角形和一个个的梯形 然后发现,第一个梯形相当于上底为
0
0
0 的梯形,差不多等价 设根节点的两个儿子的横坐标差为
a
a
a 然后可以推出下一个梯形,下下个梯形的底边宽度是多少 应该是:
2
k
+
1
−
1
2
k
\frac{2^{k+1}-1}{2^k}
2k2k+1−1 然后梯形面积公式套一下,再求和公式套一下,发现是一个等比数列,直接求和即可
代码
时间复杂度:
O
(
T
)
O(T)
O(T) 可以预处理出
p
2
[
i
]
=
(
1
2
)
n
p2[i]=(\frac{1}{2})^n
p2[i]=(21)n
#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;typedeflonglong ll;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}constint MAX =1e4+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;const ll LINF =0x3f3f3f3f3f3f3f3f;constdouble EPS =1e-5;double p2[MAX];intmain(){
p2[0]=1.0;for(int i =1;i <=10000;++i){
p2[i]= p2[i-1]/2.0;}int T;scanf("%d",&T);while(T--){int k;double xr,yr,x1,y1,x2,y2;scanf("%d",&k);scanf("%lf%lf%lf%lf%lf%lf",&xr,&yr,&x1,&y1,&x2,&y2);double h = yr - y1;double a = x2 - x1;
k-=2;double ans = a * h /2*(4.0* k -2+3.0* p2[k]);// 公式自己推吧...printf("%.3f\n",ans);}return0;}
1004 Link with Balls
题意
HDU7047 Link with Balls 有
2
n
2n
2n 个桶 第
2
x
−
1
2x-1
2x−1 个桶你可以拿
k
x
kx
kx 个球 (
k
≥
0
k\ge 0
k≥0) 第
2
x
2x
2x 个桶你最多拿
x
x
x 个球 问你拿
m
m
m 个球的方案数
样例组数
T
≤
1
0
5
T\le 10^5
T≤105
1
≤
n
,
m
≤
1
0
6
1\le n,m\le 10^6
1≤n,m≤106
思路
貌似直接就是生成函数裸题了… 第
2
t
−
1
2t-1
2t−1 个桶 的生成函数可以写成:
f
(
2
t
−
1
)
=
x
0
+
x
t
+
x
2
t
+
⋯
+
x
k
t
+
⋯
=
1
1
−
x
t
f(2t-1)=x^0 +x^{t}+x^{2t}+\cdots +x^{kt}+\cdots =\frac{1}{1-x^t}
f(2t−1)=x0+xt+x2t+⋯+xkt+⋯=1−xt1 第
2
t
2t
2t 个桶 的生成函数可以写成:
f
(
2
t
)
=
x
0
+
x
1
+
x
2
+
⋯
+
x
t
=
1
−
x
t
+
1
1
−
x
f(2t)=x^0+x^1+x^2+\cdots+x^t=\frac{1-x^{t+1}}{1-x}
f(2t)=x0+x1+x2+⋯+xt=1−x1−xt+1 最后所有桶拿完了,总的生成函数就是:
∏
f
=
f
(
1
)
⋅
f
(
2
)
⋯
f
(
2
n
)
=
[
1
1
−
x
1
⋅
1
1
−
x
2
⋯
1
1
−
x
n
]
×
[
1
−
x
2
1
−
x
⋅
1
−
x
3
1
−
x
⋯
1
−
x
n
+
1
1
−
x
]
=
1
−
x
n
+
1
(
1
−
x
)
n
+
1
\begin{aligned} \prod f&=f(1)\cdot f(2)\cdots f(2n)\\ &=\Big[ \frac{1}{1-x^1}\cdot\frac{1}{1-x^2}\cdots\frac{1}{1-x^n} \Big]\times\Big[ \frac{1-x^2}{1-x}\cdot \frac{1-x^3}{1-x}\cdots \frac{1-x^{n+1}}{1-x} \Big]\\ &=\frac{1-x^{n+1}}{(1-x)^{n+1}} \end{aligned}
∏f=f(1)⋅f(2)⋯f(2n)=[1−x11⋅1−x21⋯1−xn1]×[1−x1−x2⋅1−x1−x3⋯1−x1−xn+1]=(1−x)n+11−xn+1 最后求拿
m
m
m 个球的方案数,也就是求
[
x
m
]
[x_m]
[xm] 注意到分母部分,我们有:
1
(
1
−
x
)
n
\frac{1}{(1-x)^n}
(1−x)n1 的
[
x
m
]
=
C
m
+
n
−
1
n
−
1
[x_m]=C_{m+n-1}^{n-1}
[xm]=Cm+n−1n−1 注意到分子部分,次数为
0
0
0 或
n
+
1
n+1
n+1,两者是选其一的,所以我们对于分母部分,我们只能拿次数为
m
m
m 的与次数为
m
−
n
−
1
m-n-1
m−n−1 的 所以最终的答案为:
C
n
+
m
n
−
C
m
−
1
n
C_{n+m}^n-C_{m-1}^n
Cn+mn−Cm−1n
代码
时间复杂度:
O
(
T
+
2
e
6
)
O(T+2e6)
O(T+2e6)
ll fac[MAX],ivfac[MAX];voidinit(int n){
fac[0]=1;for(int i =1;i <= n;++i){
fac[i]= fac[i-1]* i % MOD;}
ivfac[n]=inv(fac[n]);for(int i = n-1;~i;--i){
ivfac[i]= ivfac[i+1]*(i +1)% MOD;}}
ll C(int n,int m){if(n <0|| m > n)return0;return fac[n]* ivfac[m]% MOD * ivfac[n - m]% MOD;}intmain(){init(2000000);int T =read();while(T--){int n,m;n =read();m =read();
ll ans =(C(n+m,n)-C(m-1,n)+ MOD)% MOD;Print(ans,'\n');}Write();return0;}
1005 Link with EQ
题意
HDU7048 Link with EQ 有一个长条桌子,有
n
n
n 个凳子 然后开始来人,坐进去。初始来人了,上面都没有人,就随便选一个位置来坐。 接下来,来人了,就选择其中的位置,这个位置距离其他有人的最近距离需最大;若有多个位置,则随机选一个位置 若这个最大距离为
1
1
1 ,就坐不进了,结束。 问,期望坐进去的人数?
样例组数
T
≤
1
0
5
T\le 10^5
T≤105
1
≤
n
≤
1
0
6
1\le n\le 10^6
1≤n≤106
那就好做了。我们设
d
p
[
x
]
[
3
]
dp[x][3]
dp[x][3] 数组 其中
x
x
x 表示中间一段空的位置的长度 其中
d
p
[
x
]
[
0
]
dp[x][0]
dp[x][0] 表示这段区间的左边有人坐了,中间这段区间能做多少个人(这是固定的) 其中
d
p
[
x
]
[
1
]
dp[x][1]
dp[x][1] 表示这段区间的右边有人坐了 其中
d
p
[
x
]
[
2
]
dp[x][2]
dp[x][2] 表示这段区间的左右边都有人坐了
考虑,我们最后的答案是什么?就是枚举第一个人坐的位置,然后概率乘以期望 但是貌似是
O
(
T
N
)
O(TN)
O(TN) 的呀?不要紧,我们看一下式子:
A
n
s
=
1
n
(
d
p
[
0
]
[
1
]
+
d
p
[
n
−
1
]
[
0
]
)
+
1
n
(
d
p
[
1
]
[
1
]
+
d
p
[
n
−
2
]
[
0
]
)
⋮
+
1
n
(
d
p
[
n
−
1
]
[
1
]
+
d
p
[
0
]
[
0
]
)
\begin{aligned} Ans&=\frac{1}{n}(dp[0][1]+dp[n-1][0])\\ &+\frac{1}{n}(dp[1][1]+dp[n-2][0])\\ &\qquad\qquad\qquad \vdots\\ &+\frac{1}{n}(dp[n-1][1]+dp[0][0])\\ \end{aligned}
Ans=n1(dp[0][1]+dp[n−1][0])+n1(dp[1][1]+dp[n−2][0])⋮+n1(dp[n−1][1]+dp[0][0])
原来如此,我们记两个前缀和
p
r
e
[
x
]
[
0
]
=
∑
i
=
0
n
d
p
[
i
]
[
0
]
p
r
e
[
x
]
[
1
]
=
∑
i
=
0
n
d
p
[
i
]
[
1
]
pre[x][0]=\sum_{i=0}^n dp[i][0]\\ pre[x][1]=\sum_{i=0}^n dp[i][1]\\
pre[x][0]=i=0∑ndp[i][0]pre[x][1]=i=0∑ndp[i][1] 那么答案就是:
A
n
s
=
1
n
(
p
r
e
[
n
−
1
]
[
0
]
+
p
r
e
[
n
−
1
]
[
1
]
)
Ans=\frac{1}{n}(pre[n-1][0]+pre[n-1][1])
Ans=n1(pre[n−1][0]+pre[n−1][1])
HDU7054 Yiwen with Formula 给定一个长度为
n
n
n 的序列
A
[
n
]
A[n]
A[n] 求出它的所有子序列的和的乘积 就是:
∏
b
是
a
的
子
序
列
(
∑
x
在
b
中
x
)
\prod_{b是a的子序列}\Big(\sum_{x在b中}x\Big)
b是a的子序列∏(x在b中∑x)
1
≤
n
≤
1
0
5
1\le n\le 10^5
1≤n≤105
0
≤
A
[
i
]
≤
1
0
5
0\le A[i]\le 10^5
0≤A[i]≤105 满足
∑
A
[
i
]
≤
1
0
5
\sum A[i]\le 10^5
∑A[i]≤105
思路
首先,若枚举子序列,复杂度为
O
(
2
n
×
n
)
O(2^n\times n)
O(2n×n),肯定不行 然后,我们想到背包,或者
d
p
dp
dp ,记
d
p
[
x
]
dp[x]
dp[x] 表示子序列的和为
x
x
x 的子序列的个数 最后答案就是:
A
n
s
=
∏
x
=
0
∑
A
x
d
p
[
x
]
Ans=\prod_{x=0}^{\sum A} x^{dp[x]}
Ans=x=0∏∑Axdp[x] 背包转移,复杂度是
O
(
n
2
)
O(n^2)
O(n2) 的,貌似也不大行…
但是,这个是一个
01
01
01 背包,很套路的,我们
01
01
01 背包都有第二类解法!(没多惊讶,就是自己突然就发现了!但是发现其实之前是讲过的!) 对于物品
i
i
i ,若不选,我们受益为
0
0
0 ,方案数为
1
1
1 若选,我们受益为
A
[
i
]
A[i]
A[i] ,方案数为
1
1
1 也就是对于物品
i
i
i ,我们的生成函数 为
f
(
i
)
=
(
1
+
x
A
i
)
f(i)=(1+x^{A_i})
f(i)=(1+xAi) 那么这个背包的总的生成函数当然张这个样子:
∏
f
=
(
1
+
x
A
1
)
(
1
+
x
A
2
)
⋯
(
1
+
x
A
n
)
\prod f=(1+x^{A_1})(1+x^{A_2})\cdots (1+x^{A_n})
∏f=(1+xA1)(1+xA2)⋯(1+xAn) 然后我们的答案就变成了:
A
n
s
=
∏
x
=
0
∑
A
x
(
x
项
的
系
数
)
Ans=\prod_{x=0}^{\sum A} x^{(x项的系数)}
Ans=x=0∏∑Ax(x项的系数)
但是问题又来了!这里有
n
n
n 个多项式,若我们直接用
F
F
T
FFT
FFT 去做,由于我们的最高项数为
∑
A
\sum A
∑A,所以我们的复杂度就变成了
O
(
n
2
log
n
)
\color{red}{O(n^2\log n)}
O(n2logn) ,这不是比暴力都慢? 因为我们每次都拿最大的多项式和最小的多项式去算,当然慢… 但是我们可以使用分治的工具!我们每次合并最近的那两个多项式,类似
c
d
q
cdq
cdq 分治那样,就显然更优了
还有一个问题… 因为我们直接使用
F
F
T
FFT
FFT,精度低的可怕;使用
N
T
T
NTT
NTT,要求模数为
998244353
998244353
998244353,这里的模数要求也正好是
998244353
998244353
998244353,所以我们直接套
N
T
T
NTT
NTT ?
错
了
!
!
\color{red}{错了!!}
错了!! 因为我们计算的系数其实最后是当做指数 来的,欧拉降幂的要求,就是
指
数
需
要
取
模
φ
(
P
)
=
P
−
1
\color{green}{指数需要取模 \varphi(P)=P-1}
指数需要取模φ(P)=P−1 所以我们只能使用 任意模数
M
T
T
MTT
MTT ,貌似有两种做法,一种是把数字拆成
x
=
a
M
+
b
x=aM+b
x=aM+b 然后去做几遍
F
F
T
FFT
FFT 保证精度;或者取多个质数模数,然后使用
C
R
T
CRT
CRT 合并答案,应该都是可以的
还有一个小优化,如果
A
i
=
0
A_i=0
Ai=0 了,答案就直接是
0
0
0 了,也是容易得到的
代码
时间复杂度:
O
(
n
log
2
n
)
O(n\log^2 n)
O(nlog2n)
#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;typedeflonglong ll;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}constint MAX =2e5+50;constint MOD =998244353;constint INF =0x3f3f3f3f;const ll LINF =0x3f3f3f3f3f3f3f3f;constdouble EPS =1e-5;
ll qpow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a%MOD;a=a*a%MOD;n>>=1;}return res;}
ll qpow(ll a,ll n,ll p){a%=p;ll res =1LL;while(n){if(n&1)res=res*a%p;a=a*a%p;n>>=1;}return res;}
ll npow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a;a=a*a;n>>=1;if(res<0||a<0)return0;}return res;}
ll inv(ll a){/* */returnqpow(a,MOD-2);}
ll inv(ll a,ll p){returnqpow(a,p-2,p);}
namespace MTT
{typedeflonglong ll;typedeflongdouble ld;constint MAXP=1<<20;// const int MOD=998244353;constint PHI=MOD-1;constint M=32768;const ld pi=acos(-1.0);structcp{
ld x,y;cp(){x=y=0;}cp(ld _x,ld _y){x=_x,y=_y;}
friend cp operator +(cp l,cp r){returncp(l.x+r.x,l.y+r.y);}
friend cp operator -(cp l,cp r){returncp(l.x-r.x,l.y-r.y);}
friend cp operator *(cp l,cp r){returncp(l.x*r.x-l.y*r.y,l.x*r.y+r.x*l.y);}}a1[MAXP+5],a2[MAXP+5],b1[MAXP+5],b2[MAXP+5],c1[MAXP+5],c2[MAXP+5],c3[MAXP+5];int rev[MAXP+5];voidFFT(cp *a,int len,int typ){int lg=31-__builtin_clz(len);for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));for(int i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);for(int i=2;i<=len;i<<=1){
cp W=cp(cos(2*pi/i),typ*sin(2*pi/i));for(int j=0;j<len;j+=i){
cp w=cp(1,0);for(int k=0;k<(i>>1);k++,w=w*W){
cp X=a[j+k],Y=w*a[(i>>1)+j+k];
a[j+k]=X+Y;a[(i>>1)+j+k]=X-Y;}}}if(typ==-1)for(int i=0;i<len;i++)a[i].x=ll(a[i].x/len+0.5);}
vector<int>conv(vector<int> a,vector<int> b){
vector<int> res;int LEN=1;while(LEN<a.size()+b.size())LEN<<=1;for(int i=0;i<LEN;i++)a1[i]=a2[i]=b1[i]=b2[i]=c1[i]=c2[i]=c3[i]=cp(0,0);for(int i=0;i<a.size();i++)a1[i].x=a[i]/M,a2[i].x=a[i]%M;for(int i=0;i<b.size();i++)b1[i].x=b[i]/M,b2[i].x=b[i]%M;FFT(a1,LEN,1);FFT(a2,LEN,1);FFT(b1,LEN,1);FFT(b2,LEN,1);for(int i=0;i<LEN;i++)c1[i]=a1[i]*b1[i],c2[i]=a1[i]*b2[i]+a2[i]*b1[i],c3[i]=a2[i]*b2[i];FFT(c1,LEN,-1);FFT(c2,LEN,-1);FFT(c3,LEN,-1);for(int i=0;i+1<a.size()+b.size();i++)
res.push_back((1LL*((ll)(c1[i].x)%PHI)*M%PHI*M%PHI+1LL*((ll)(c2[i].x)%PHI)*M%PHI+(ll)(c3[i].x)%PHI)%PHI);return res;}};
using namespace MTT;int aa[MAX];
vector<int>cdq(int l,int r){if(l == r){
vector<int>res(aa[l]+1,0);
res[0]++;
res[aa[l]]++;return res;}int mid = l + r >>1;returnconv(cdq(l,mid),cdq(mid+1,r));}intmain(){int T =read();while(T--){int n =read();int sum =0;for(int i =1;i <= n;++i)aa[i]=read(),sum += aa[i];
vector<int>V =cdq(1,n);
ll ans =qpow(0,V[0]-1);for(int i =1;i <= sum;++i)ans = ans *qpow(i,V[i])% MOD;Print(ans,'\n');}Write();return0;}