H y p e r l i n k Hyperlink Hyperlink
https://www.lydsy.com/JudgeOnline/problem.php?id=2111
https://www.luogu.org/problem/P2606
D e s c r i p t i o n Description Description
求有多少个长度为 n n n的序列 A A A,对于所有的 2 ≤ i ≤ n 2\leq i\leq n 2≤i≤n,都有 A i ≥ A ⌊ i 2 ⌋ A_i\geq A_{\lfloor\frac i2\rfloor} Ai≥A⌊2i⌋,求序列个数,对 1 0 9 + 7 10^9+7 109+7取模
数据范围: n ≤ 1 0 6 n\leq 10^6 n≤106
S o l u t i o n Solution Solution
f u c k fuck fuck现这个序列的性质和堆很像,构造出堆后树形 d p dp dp即可
f [ k ] = C t k − 1 t l s o n × f [ l s o n ] × f [ r s o n ] f[k]=C_{t_k-1}^{t_{lson}}\times f[lson]\times f[rson] f[k]=Ctk−1tlson×f[lson]×f[rson]
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)构造复杂度
C o d e Code Code
在bzoj上可能A不了
#include<cstdio>
#include<cctype>
#define lson k<<1
#define rson k<<1|1
using namespace std;typedef long long LL;
const int N=1000006;
int n,a[N];
LL fac[N]={1,1},inv[N]={1,1},f[N],p;
inline LL read()
{
char c;LL f=0,d=1;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline LL ksm(LL x,LL y)
{
LL ans;
for(ans=1;y;(x*=x)%=p,y>>=1) if(y&1)(ans*=x)%=p;
return ans;
}
inline LL C(LL n,LL m){if(n<m) return 0;return (fac[n]*inv[m]%p*inv[n-m]%p)%p;}
inline LL Lucas(LL n,LL m){if(!m)return 1;return C(n%p,m%p)*Lucas(n/p,m/p)%p;}
inline LL solve(int k)
{
int x=a[k];
if(x<3) return 1;
if(x==3) return 2;
int u=a[lson],v=a[rson];
if(f[u]==0) f[u]=solve(lson);
if(f[v]==0) f[v]=solve(rson);
return Lucas(x-1,u)*f[u]%p*f[v]%p;
}
signed main()
{
n=read();p=read();
for(register int i=2;i<=n;i++) fac[i]=(long long)fac[i-1]*i%p;
inv[n-1]=ksm(fac[n-1],p-2);
for(register int i=n-2;i>1;i--) inv[i]=(1ll*inv[i+1]*(i+1))%p;
for(register int i=1,k;i<=n;i++)
{
k=i;
while(k) a[k]++,k>>=1;
}
printf("%lld\n",solve(1));
}