2022.7.15 AGC047D&AGC047E&AGC028E
AGC047D Twin Binary Tree
分治,剩下的内容是 trivial 的。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline int ksm(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%mod;
x=1ll*x*x%mod;y>>=1;
}return res;
}
int n,m,vl[1<<18],iv[1<<18],ans,S[1<<18],p[1<<18];
inline void solve(int h,int l,int r){
if(l==r)return;
int mid=(l+r)>>1,tot=0;
for(int i=l;i<=mid;i++){
int now=p[i],res=vl[i];
while(now)res=1ll*res*now%mod,S[now]=(S[now]+res)%mod,now>>=1;
}
for(int i=mid+1;i<=r;i++){
int now=p[i],res=vl[i],fin=0;
while(now){
tot=(tot+1ll*res*(S[now]-1ll*fin*now%mod+mod))%mod;
res=1ll*res*now%mod,fin=S[now],now>>=1;
}
}
for(int i=l;i<=mid;i++){
int now=p[i];
while(now)S[now]=0,now>>=1;
}
ans=(ans+1ll*tot*iv[h]%mod*iv[h>>1])%mod;
solve(h<<1,l,mid);solve(h<<1|1,mid+1,r);
}
int main(){
n=read();vl[0]=iv[0]=1;
for(int i=1;i<(1<<n);i++){
vl[i]=1ll*vl[i>>1]*i%mod;
iv[i]=ksm(vl[i],mod-2);
}int bas=(1<<n-1);
for(int i=1;i<=bas;i++)
p[i+bas-1]=read()+bas-1;
//for(int i=bas;i<(1<<n);i++)
// printf("%d ",p[i]);puts("");
solve(1,bas,(1<<n)-1);
printf("%d\n",ans);
return 0;
}
AGC028E High Element
瞎扯:考虑一波可行性判断。考虑那些在原序列中就是前缀最大值的位置,若为偶数个,则非常好构造;若为奇数个,那么一个简单的想法就是我每边取一半,然后在前后找一个补位的即可。形式化地,假如位置集合为 \(p_1,p_2,...,p_k\),在 \([1,p_{\frac{k-1}{2}}]\) 中除了这些数没有比 \(p_{\frac{k+1}{2}}\) 要小的,在 \([p_{\frac{k+1}{2}},n]\) 中没有比 \(p_{\frac{k-1}2}\) 要大的。