• 洛谷3732:[HAOI2017]供给侧改革——题解


    https://www.luogu.org/problemnew/show/P3732

    Anihc国提高社会生产力水平.落实好以人民为中心的发展思想。决定进行供给侧结构性改革。

    为了提高供给品质.你调查了某个产业近来n个时期的供求关系平衡情况.每个时期的情况都用0或1中的一个数字来表示.于是这就是—个长度为n的01字符串S。为了更好的了解这一些数据.你需要解决一些询问.我们令data(l,r)表示:在字符串S中.起始位置在[l,r]之间的这些后缀之中,具有最长公共前缀的两个后缀的最长公共前缀的长度。

    对于每一个询问L,R.求sigma(data(i,R))。

    由于你其实根本没有时间调查,所以这些数据都是乱编的,即串S中的每一位都是在0和1之间随机产生的。

    参考:https://msy.blog.luogu.org/solution-p3732

    最后一句话很皮,于是我们思考下发现公共前缀一定很短,连(看)猜(题)带(解)蒙大概是40吧。

    于是我们把询问离线,按照$r$排序,从左到右扫一遍$i$,将以$i$为首的40位字符加入到trie树中,以此维护$pos[k]$表示最小的区间$[pos[k],i]$,使得$data(pos[k],i)=k$。

    (还是很好维护的,如果不知道怎么维护可以看参考也可以直接看代码。)

    为什么我们构造了$pos$数组呢?其实是因为$data$的单调不增性。

    由此我们发现$data(pos[k+1]+1,i)$到$data(pos[k],i)$都是$k$。

    答案就呼之欲出了。

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int a[2],ed;
    }tr[N*40];
    struct data{
        int l,r,id;
    }d[N];
    char s[N];
    int n,q,tot,pos[50];
    ll ans[N];
    inline bool cmp(data a,data b){
        return a.r<b.r;
    }
    void insert(int st){
        int now=0;
        for(int i=st;i<=min(n,st+39);i++){
            int w=s[i]-'0';
            if(!tr[now].a[w])tr[now].a[w]=++tot;
            now=tr[now].a[w];
            if(tr[now].ed)
                pos[i-st+1]=max(pos[i-st+1],tr[now].ed-i+st);
            tr[now].ed=i;
        }
    }
    int main(){
        n=read(),q=read();
        scanf("%s",s+1);
        for(int i=1;i<=q;i++){
            d[i].l=read(),d[i].r=read();
            d[i].id=i;
        }
        sort(d+1,d+q+1,cmp);
        for(int i=1,j=1;i<=n;i++){
            insert(i);
            while(j<=q&&d[j].r==i){
                for(int k=1;k<=40;k++){
                    if(pos[k]>=d[j].l){
                        ans[d[j].id]+=(ll)k*(pos[k]-max(pos[k+1],d[j].l-1));
                    }else break;
                }
                j++;
            }
        }
        for(int i=1;i<=q;i++)printf("%lld
    ",ans[i]);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Java 排序(快排,归并)
    Java 编译???
    装箱 拆箱
    Integer-->String String-->Integer
    java 内部类
    Java 反射机制
    Java 多态的实现机制
    一个句子,找出最字符最少的关键词
    重载、重写
    数组有没有length()这个方法? String有没有length()这个方法?
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9226685.html
Copyright © 2020-2023  润新知