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}\) 要大的。

posted @ 2022-07-13 22:19  syzf2222  阅读(30)  评论(0编辑  收藏  举报