HDU 6305 RMQ Similar Sequence(笛卡尔树/概率)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oidoidoid/article/details/82913340

题目链接

昨天

对着

题解

看了好久

也没看懂

那个n!是要干什么

题解大概是这样\frac{n!}{\prod size[i]}

虽然还是没懂这个公式是什么意思,但是我知道为什么答案是\frac{n}{2*\prod size[i]}了,手动狗头

逆元打表的代码

void inverse(ll n, ll mod) {
    inv[1] = 1;
    for (int i=2; i<=n; ++i) {
        inv[i] = (ll) (mod - mod / i) * inv[mod%i] % mod;
    }
}

思路:

1.学习了一下笛卡尔树

笛卡尔树就是一棵树,树上的每个节点代表序列中的一个位置。

中序遍历即得原序列

子树中的所有节点的值均大于(小于)根节点

对于一个序列可以O(n)建树

2.发现A序列和B序列RMQ similar就是A序列和B序列的笛卡尔树长的一样

3.计算一个序列和A序列笛卡尔树一样的概率乘以n/2

概率的计算就是每个节点的子树节点个数的倒数相乘,即当前节点在这个递归的区间里是最大值的概率

建笛卡尔树的代码

void build(){
		go(i,1,n){
			scanf("%d",&a[i]); ls[i]=rs[i]=0;
			if (a[i]<=a[stk[top]]||top==0){
				rs[stk[top]]=i;
				fa[i]=stk[top];
				stk[++top]=i;
			}
			else{
				while (a[stk[top]]<a[i]&&top>=1) top--;
				rs[stk[top]]=i;
				fa[i]=stk[top];
				ls[i]=stk[top+1];
				fa[stk[top+1]]=i;
				stk[++top]=i;
			}
		}
}

本题AC代码

#include<iostream>
#include<algorithm>
#include<stack>
#include<string.h>
#define go(i,a,b) for (int i=a;i<=b;i++)
#define N 1000005
#define MOD 1000000007
#define ll long long
using namespace std;
int stk[N],top,rs[N],ls[N],fa[N],a[N];
ll ans,inv[N];

void inverse(ll n, ll mod) {
    inv[1] = 1;
    for (int i=2; i<=n; ++i) {
        inv[i] = (ll) (mod - mod / i) * inv[mod%i] % mod;
    }
}

ll dfs(ll u){
	if (!rs[u]&&!ls[u]) return 1;
	int tot=0;
	if (rs[u]) tot+=dfs(rs[u]);
	if (ls[u]) tot+=dfs(ls[u]);
	tot++;
	ans=ans*inv[tot]%MOD;
	return tot;
}
ll mod(ll x){
	while (x>=MOD) x-=MOD;
	return x;
}
int main(){
	inverse(N-5,MOD);
	int T,n;
	scanf("%d",&T);
	while (T--){
		scanf("%d",&n);
		top=0;
		ans=1;
		go(i,1,n){
			scanf("%d",&a[i]); ls[i]=rs[i]=0;
			if (a[i]<=a[stk[top]]||top==0){
				rs[stk[top]]=i;
				fa[i]=stk[top];
				stk[++top]=i;
			}
			else{
				while (a[stk[top]]<a[i]&&top>=1) top--;
				rs[stk[top]]=i;
				fa[i]=stk[top];
				ls[i]=stk[top+1];
				fa[stk[top+1]]=i;
				stk[++top]=i;
			}
		}
		go(i,1,n) if (fa[i]==0) dfs(i);
		ans=ans*inv[2]%MOD*n%MOD;
		cout<<ans<<endl;
	} 
	return 0;
}

刚开始ls和rs写了两个memset,实力TLE,改成for循环赋值过了。

猜你喜欢

转载自blog.csdn.net/oidoidoid/article/details/82913340
今日推荐