HDU 6305 RMQ Similar Sequence
阿新 • • 發佈:2018-12-12
昨天
對著
題解
看了好久
也沒看懂
那個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;
}
}
思路:
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迴圈賦值過了。