题解:P13037 [GCJ 2021 #2] Hidden Pancakes
qiuqiu_luogu · · 题解
首先这道题一眼排列计数。
然后考虑最大的煎饼所在位置。
不难发现最大的煎饼就是在最右边的
感性证明一下,最大的煎饼覆盖完之后肯定是
所以以最大的煎饼为分界点,将序列分成两段,对右半段
一次划分对答案的贡献为
所以共有
找最大的煎饼也就是找区间最右边的
时间复杂度约为
实现时,维护最小值可以不对右半段
CODE
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+20,mod=1e9+7;
int qpow(int a,int b,int md){
if(a==0)return 0;
int ans=1;
while(1){
if(b==0)break;
if(b&1)ans=(ans*a)%md;
a=a*a%md;
b>>=1;
}
return ans;
}
int fc[N+10],infc[N+10];
int C(int n,int m){
return fc[n]%mod*infc[m]%mod*infc[n-m]%mod;
}
void init(){
fc[0]=infc[0]=1;
for(int i=1;i<=N;i++)
fc[i]=fc[i-1]*i%mod,
infc[i]=qpow(fc[i],mod-2,mod)%mod;
}
int n;
int wh[N*4],a[N];
#define mid ((l+r)>>1)
void build(int p,int l,int r){
if(l==r){wh[p]=l;return;}
build(p*2,l,mid);
build(p*2+1,mid+1,r);
if(a[wh[p*2]]<a[wh[p*2+1]])wh[p]=wh[p*2];
else wh[p]=wh[p*2+1];//右边优先
}
void clear__(int p,int l,int r){
if(l==r){wh[p]=0;return;}
build(p*2,l,mid);
build(p*2+1,mid+1,r);
wh[p]=0;
}
int ask(int p,int l,int r,int L,int R){
if(L<=l&&r<=R){return wh[p];}
int ans1=0,ans2=0;
if(L<=mid)ans1=ask(p*2,l,mid,L,R);
if(mid+1<=R)ans2=ask(p*2+1,mid+1,r,L,R);
if(ans1==0||ans2==0)return ans1+ans2;
if(a[ans1]<a[ans2])return ans1;
return ans2;
}
int ans=1;
void f(int l,int r){
if(l>=r)return;
int w=ask(1,1,n,l,r);
f(l,w-1);
f(w+1,r);
ans=(ans*C(r-l,w-l))%mod;
}
int one(){
ans=1;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]-a[i-1]>1||a[i]>i)ans=0;
}
if(ans==0)return 0;
build(1,1,n);
f(1,n);
return ans;
}
signed main(){
init();
int T;
scanf("%lld",&T);
for(int i=1;i<=T;i++){
printf("Case #%lld: %lld\n",i,one());
}
return 0;
}