2020牛客暑期多校训练营(第三场) H Sort the Strings Revision —— 笛卡尔树,有丶东西

This way

题意:

给你一个长度为n的串s0,然后现在有一个长度为n的排列p和一个长度为n的d,从0开始到n-1,每次都有一个操作: s i + 1 = s i s_{i+1}=s_i ,然后替换掉 s i + 1 s_{i+1} 的第p[i]个字符为d[i]。问你这n+1个字符串的字典序。

题解:

太强了,根本想不到啊
首先以位置为顺序,p的大小为优先级建立笛卡尔树,注意如果d[i]==p[i]%10,就是说如果改了这个点的值根没改一样,那么就将p[i]设为inf,表示它一定是最后的,在这道题,表示它统治的区间就是它这个点本身。
笛卡尔树建立完以后,每个点表示它统治的区间:
在这里插入图片描述
就比如红色点的修改只会影响到在红色点区间内的值的排名,因为最上面那个黑色的点修改了之后,要么就是在它之后修改的数比前面的数全都大,要么就是全都小,所以红色点修改的情况不会影响到蓝色的点(自行理解一下)。
然后考虑每个区间的排名,拿红色的点举例子,如果它修改的值比原来的值要小,那么在这个位置之后修改的位置,一定比这个区间内在这个位置之前修改的值都要小。
所以dfs(l,root,ls[root],no+(p[root]%10>d[root])*(r-root));
反之亦然。
并且修改一个位置,会影响到下一个位置的排名,所以dfs的时候不是(l,root-1)而是(l,root)。
如果当前p[root]==inf的话,表示它所统治的区间,所有值都是不变的,那么就按照位置顺序排名。
tql/QAQ.jpg

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e6+5;
const ll mod=1e9+7,sed=10000019;
int ls[N],rs[N],fa[N],st[N],top,p[N],d[N];
int n;
void build(){
    for(int i=0;i<n;i++){
        int f=0;
        while(top&&p[st[top]]>p[i])
            top--,f=1;
        if(top)fa[i]=st[top],rs[st[top]]=i;
        if(f)ls[i]=st[top+1],fa[ls[i]]=i;
        st[++top]=i;
    }
}
ll ans[N];
void dfs(int l,int r,int root,int no){
    if(l==r){
        ans[l]=no;
        return ;
    }
    if(p[root]==n){
        for(int i=0;i<=r-l+1;i++)
            ans[l+i]=no+i;
        return ;
    }
    dfs(l,root,ls[root],no+(p[root]%10>d[root])*(r-root));
    dfs(root+1,r,rs[root],no+(p[root]%10<d[root])*(root-l+1));
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++)ls[i]=rs[i]=fa[i]=0;
        top=0;
        int ps,pa,pb,pm;
        scanf("%d%d%d%d",&ps,&pa,&pb,&pm);
        for(int i=0;i<n;i++)p[i]=i;
        for(int i=1;i<n;i++)
            swap(p[ps%(i+1)],p[i]),ps=(1ll*ps*pa+pb)%pm;
        scanf("%d%d%d%d",&ps,&pa,&pb,&pm);
        for(int i=0;i<n;i++)
            d[i]=ps%10,ps=(1ll*ps*pa+pb)%pm,p[i]=d[i]==p[i]%10?n:p[i];
        build();
        dfs(0,n,st[1],0);
        ll mul=1,sum=0;
        for(int i=0;i<=n;i++)
            sum=(sum+ans[i]*mul)%mod,mul=mul*sed%mod;
        printf("%lld\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/107567094
今日推荐