1. 程式人生 > >HDU 6305 RMQ Similar Sequence

HDU 6305 RMQ Similar Sequence

題目連結

昨天

對著

題解

看了好久

也沒看懂

那個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迴圈賦值過了。