版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oidoidoid/article/details/82913340
昨天
对着
题解
看了好久
也没看懂
那个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循环赋值过了。