• HDU 4455 Substrings --递推+树状数组优化


    题意: 给一串数字,给q个查询,每次查询长度为w的所有子串中不同的数字个数之和为多少。

    解法:先预处理出D[i]为: 每个值的左边和它相等的值的位置和它的位置的距离,如果左边没有与他相同的,设为n+8(看做无穷)。

    考虑已知w=k的答案,推w = k+1时,这时每个区间都将增加一个数,即后n-k个数会增加到这些区间中,容易知道,如果区间内有该数,那么个数不会加1,,即D[i] > k时,结果++,即查询后n-k个数有多少个D[i] > k 的数即为要加上的数,然后最后面还会损失一个区间,损失的是不能增加一个数的那个区间,随着w的增加,该区间会向左边伸展,所以记录一下该区间有多少个不同的数即可。 求区间内有多少个D[i]>k可以用树状数组先求有多少个D[i]<=k(getsum(k)),然后区间长度减一下即可。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define lll __int64
    using namespace std;
    #define N 1000107
    
    int c[N],n,D[N],Last,vis[N],a[N],pos[N],L[N];
    lll sum[N];
    
    int lowbit(int x) { return x&-x; }
    void modify(int x,int val)
    {
        while(x <= n+10)
        {
            c[x]+=val;
            x += lowbit(x);
        }
    }
    
    int getsum(int x)
    {
        int res = 0;
        while(x > 0)
        {
            res += c[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    int main()
    {
        int q,i,j,w;
        while(scanf("%d",&n)!=EOF && n)
        {
            for(i=1;i<=n;i++)
                scanf("%d",&a[i]);
            memset(pos,0,sizeof(pos));
            for(i=1;i<=n;i++)
            {
                int x = a[i];
                D[i] = i-pos[x];
                if(D[i] == i) D[i] = n+8;
                pos[x] = i;
            }
            memset(c,0,sizeof(c));
            memset(vis,0,sizeof(vis));
            for(i=2;i<=n;i++)
                modify(D[i],1);
            sum[1] = n;
            Last = 1;
            vis[a[n]] = 1;
            for(i=2;i<=n;i++)
            {
                sum[i] = sum[i-1]+(n-i+1-getsum(i-1))-Last;
                modify(D[i],-1);
                if(!vis[a[n-i+1]])
                {
                    vis[a[n-i+1]] = 1;
                    Last++;
                }
            }
            scanf("%d",&q);
            while(q--)
            {
                scanf("%d",&w);
                printf("%I64d
    ",sum[w]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Step by step Dynamics CRM 2013安装
    SQL Server 2012 Managed Service Account
    Step by step SQL Server 2012的安装
    Step by step 活动目录中添加一个子域
    Step by step 如何创建一个新森林
    向活动目录中添加一个子域
    活动目录的信任关系
    RAID 概述
    DNS 正向查找与反向查找
    Microsoft Dynamics CRM 2013 and 2011 Update Rollups and Service Packs
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4084054.html
Copyright © 2020-2023  润新知