zoukankan      html  css  js  c++  java
  • 【JZOJ4804】【NOIP2016提高A组模拟9.28】成绩调研

    题目描述

    这里写图片描述

    输入

    这里写图片描述

    输出

    这里写图片描述

    样例输入

    5 3
    1 2 3 1 2
    1 2
    1 1
    1 1

    样例输出

    4

    数据范围

    这里写图片描述

    解法

    考虑设置左指针l和右指针r;
    维护[l,r]的关于等第的桶。
    初始l=r=0;
    每次右移r,加入新元素a[r];
    如果桶因此爆了上限,则右移l并剔除a[l]直至桶不再爆上线。
    (“桶爆上限”定义:某一元素的计数超过给定的区间的右端点)
    每次右移结束后,如果所有元素的计数位于各自给定区间之内;
    则就称这个[l,r]可以对答案进行贡献;


    贡献的方式:
    假定[l,r]区间内可以对答案进行贡献,
    简单想一个O(n)的贡献方法,一直把l向右移直至[l,r]不再可以对答案贡献为止。
    考虑优化,显然容易确定对于每种等第最多向右移多少位以保证区间可以进行贡献,设为x[i]。
    那么贡献就等于所有x[i]的最小值。
    在右移的时候顺便用线段树维护这个x。


    题解给出了一种O(n)的方法。

    代码

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #include<algorithm>
    #define ll long long
    #define ln(x,y) ll(log(x)/log(y))
    #define sqr(x) ((x)*(x))
    using namespace std;
    const char* fin="survey.in";
    const char* fout="survey.out";
    const ll inf=0x7fffffff;
    const ll maxn=200007,maxt=maxn*4;/*注意!!!!!!!!*/
    ll n,m,i,j,k,cnt,head,tmp;
    ll ans;
    ll a[maxn],tong[maxn],b[maxn][2];
    ll c[maxt],fi[maxn],ta[maxn],ne[maxn],key[maxn];
    bool bz=false;
    void change(ll l,ll r,ll t,ll v,ll v1){
        ll mid=(l+r)/2;
        if (l==r) {
            c[t]=v1;
            return;
        }
        if (v<=mid) change(l,mid,t*2,v,v1);
        else change(mid+1,r,t*2+1,v,v1);
        c[t]=min(c[t*2],c[t*2+1]);
    }
    ll getmin(ll l,ll r,ll t,ll v1,ll v2){
        ll mid=(l+r)/2;
        if (l>v2 || r<v1) return inf;
        if (l>=v1 && r<=v2) return c[t];
        return min(getmin(l,mid,t*2,v1,v2),getmin(mid+1,r,t*2+1,v1,v2));
    }
    int main(){
        freopen(fin,"r",stdin);
        freopen(fout,"w",stdout);
        scanf("%d%d",&n,&m);
        memset(c,127,sizeof(c));
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        for (i=1;i<=m;i++) {
            scanf("%d%d",&b[i][0],&b[i][1]);
            if (b[i][0]==0) cnt++;
        }
        head=1;
        for (i=1;i<=n;i++){
            if (fi[a[i]]==0) fi[a[i]]=ta[a[i]]=i;
            else ne[ta[a[i]]]=ta[a[i]]=i;
            if (tong[a[i]]>=b[a[i]][0]){
                tong[a[i]]++;
                if (b[a[i]][0]==0) change(1,m,1,a[i],inf);
                else {
                    key[a[i]]=ne[key[a[i]]],change(1,m,1,a[i],key[a[i]]);
                }
                while (tong[a[i]]>b[a[i]][1]){
                    bz=false;
                    if (tong[a[head]]>=b[a[head]][0]) bz=true;
                    tong[a[head]]--;
                    fi[a[head]]=ne[fi[a[head]]];
                    if (tong[a[head]]<b[a[head]][0] && bz) cnt--;
                    head++;
                }
            }else{
                tong[a[i]]++;
                if (tong[a[i]]==b[a[i]][0]){
                    cnt++;
                    key[a[i]]=fi[a[i]];
                    change(1,m,1,a[i],key[a[i]]);
                }
            }
            if (cnt==m) {
                ans+=getmin(1,m,1,1,m)-head+1;
            }
        }
        printf("%lld",ans);
        return 0;
    }

    启发

    线性维护区间时,不妨考虑设置左右指针。
    再联系数据结构来进行优化。

  • 相关阅读:
    六种常见排序算法的自我研究(冒泡排序,选择排序,快速排序,归并排序,插入排序,堆排序)
    设计模式学习总结(二)工厂模式
    SQL Server Reporting Service(SSRS) 第七篇 常见错误汇总
    SQL Server Reporting Service(SSRS) 第六篇 SSRS 部署总结
    设计模式学习总结(一)简单工厂模式
    设计模式学习总结(三)抽象工厂模式
    设计模式学习总结(四)单例模式
    SQL Server覆盖索引--有无包含列对数据库查询性能的影响分析
    Dev Express Report 学习总结(八)Dev Express Reports 常见问题总结
    docker命令笔记
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714884.html
Copyright © 2011-2022 走看看