• Codeforces 786C Till I Collapse(树状数组+扫描线+倍增)


    【题目链接】 http://codeforces.com/contest/786/problem/C

    【题目大意】

      给出一个数列,问对于不同的k,将区间划分为几个,
      每个区间出现不同元素个数不超过k时最少的区间划分数量。

    【题解】

      我们可以用树状数组+扫描线求出一个区间不同元素的数量,
      我们记录每一个位置上下一个相同相同元素的位置,当扫描线扫过当前点时
      我们消除这个点的影响,并在其下个出现的位置进行更新,
      这样就能求出固定左端点不同右端点情况下不同区间内不同元素的数量,
      这个题我们可以用倍增找出对于每个k在扫描到的当前点,
      下一个满足限制条件的最远点在哪里,然后在那里保存下这个k,
      当扫描到那里的时候继续计算,查询的次数就是区间的数目。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <vector> 
    using namespace std;
    const int N=1000100;
    vector<int> f[N];
    int n,m,a[N],c[N],pre[N],nxt[N],ans[N];
    void add(int x,int val){while(x<=n+1)c[x]+=val,x+=x&-x;}
    int find(int x){
        int p=0;
        for(int i=20;i>=0;i--){
            if(p+(1<<i)<=n+1&&c[p+(1<<i)]<x){
                x-=c[p+(1<<i)];
                p+=(1<<i);
            }
        }return p+1;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n+1;i++)pre[i]=n+1;
        for(int i=n+1;i>=1;i--){
    	    nxt[i]=pre[a[i]];
            pre[a[i]]=i;
        }
        for(int i=1;i<=n+1;i++)add(pre[i],1),f[1].push_back(i);
        for(int i=1;i<=n;i++){
            int w=f[i].size();
            for(int j=0;j<w;j++){
                int d=f[i][j];
                int pos=find(d+1);
                ans[d]++;
                f[pos].push_back(d);
            }add(i,-1),add(nxt[i],1);
        }for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'
    ':' ');
        return 0;
    }
  • 相关阅读:
    js-AOP
    jQueryUI之autocomplete
    nginx安装配置
    oracle结构语法
    ajax/表单提交 多个相同name的处理方法
    ES6模块化
    docker运维
    帆软报表
    oracle锁表
    香港到大陆IPLC节点故障
  • 原文地址:https://www.cnblogs.com/forever97/p/codeforces786c.html
Copyright © 2020-2023  润新知