HDU 4455

题意 :

题目

给你一个序列 , 查询 t ,问  序列 连续 长度为 t 的子区间 的不同数 的和

巧妙的动态规划

数据大, Dp可以 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 1e6 +131;
typedef long long ll;
ll Dp[maxn]; ///总数
int Num[maxn]; /// 数列
int Suf[maxn]; /// 后 i 个数中不同的个数
int Flag[maxn]; /// 标记 数组
int Cnt[maxn];  /// 统计 两个相同的数 相间 i 有多少个。

int main()
{
    int n, q;
    int tmp;
    while(~scanf("%d",&n) && n)
    {
        memset(Dp,0,sizeof(Dp));
        memset(Suf,0,sizeof(Suf));
        memset(Flag,0,sizeof(Flag));
        memset(Cnt,0,sizeof(Cnt));
        for(int i = 1; i <= n; ++i)
        {                            ///这里Flag数组标记Num【i】上一次出现的位置
            scanf("%d",&Num[i]);
            Cnt[i-Flag[Num[i]]]++;   ///
            Flag[Num[i]] = i;        /// 更新位置
        }
        memset(Flag,0,sizeof(Flag));
        Suf[1] = Flag[Num[n]] = 1;   /// 这里Flag数组标记 Num【i】 在后 K个中是否出现过
        for(int i = 2; i <= n; ++i)  /// 方便统计 Suf 数组
        {
            if(Flag[Num[n-i+1]] == 0)
            {
                Flag[Num[n-i+1]] = 1;
                Suf[i] = Suf[i-1]+ 1;
            }else Suf[i] = Suf[i-1];
        }

        int sum = n;
        Dp[1] = n;
        for(int i = 2; i <= n; ++i)
        {
            Dp[i] = Dp[i-1] - Suf[i-1];  /// Dp【i】 为 上一个 的总数  - 最后多出来的 Suf【i】
            sum -= Cnt[i-1];             /// 然后 sum 减去 相距 i-1 的 重复次数,
            Dp[i] += sum;                /// Dp【i】 有多个子区间, 再 加上 sum;
        }
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&tmp);
            printf("%lld\n",Dp[tmp]);
        }
    }
    return 0;
}
时间: 2024-10-29 19:10:54

HDU 4455的相关文章

hdu 4455 Substrings(树状数组+递推)

题目链接:hdu 4455 Substrings 题目大意:给定一个长度为N的序列,现在有Q次询问,每次给定一个w,表示长度,输出序列中长度为w的连续子序列 的权值和.序列的权值表示序列中不同元素的个数. 解题思路:递推,先预处理处每个位置和前面相同的数据的最短距离P.dp[i]表示说长度为i子序列的权值和,dp[i+1] = dp[i] + v - c.v为[i+1~N]中P值大于i的个数,我们可以看作将长度为i的子序列长度向后增加1,那么v则为增加长度带来 的权值增加值,c则是最后一个长度为

Substrings(hdu 4455)

题意: 给定一个序列ai,个数为n.再给出一系列w:对于每个w,求序列中,所有长度为w的连续子串中的权值和,子串权值为子串中不同数的个数. /* dp[i]表示长度为i的序列不同元素个数之和. 考虑从i-1向i转移的时候,最后i-1个元素的贡献会消失,记last[i]表示最后i个元素中不重复元素的个数,则转移时,它的贡献是-last[i]. 同时每个序列会多出a[i],a[i+1],a[i+2]等元素,这些元素对答案有贡献的前提是与前i-1个元素不重复. 那么i这个元素对答案有贡献的范围是pos

HDU 4455 Substrings(DP)

题目链接:点击打开链接 思路: 我们用d[i]表示长度为i的答案.   那么我们可以把样例数据写出来看看是否能够递推.   可以发现, d[i] = d[i-1] - last[i-1] + (n-i+1) - dist[i]. last[i]表示从后往前i长度时不同数字的个数, 也就是说, d[i-1]的最后一个子序列被扔了, 然后d[i]比d[i-1]还可能多加了( n - i + 1), 然后我们把不符合要求的减掉.  比赛时自己推出来的, 说不很清楚, 建议自己推一下. 细节参见代码:

hdu 4455 Substrings

比赛的时候一直往离线+数据结构上想 sigh,不过最后正解中也的确带有 "离线处理" --------------------------------------------------------------------------------------------------------------------------------- 首先我们可以很明显地发现 区间个数是$nq$级别的 所以莫队什么的还不如直接暴力 然后 我们还可以估计得出最后的答案是可以爆$int$的 所以直

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 的数即为要加上的数,然后最后面还会损失一个区间,损失的

HDU 4455 Substrings(预处理+dp)

题目大意:给你n个数字,然后m次查询,每次给你一个x,让你求出来1到x,2到x+1...不同数的和. 需要各种预处理,处理出来所有的间隔之间有多少相同的数字,处理出来最后一个被去掉的间隔有多少个不重复的数字. dp[i] = dp[i-1]-S+T.S代表最后被略去的那个区间的不同的数,T代表新区间扩张之后每个区间增加的不同的数的和. Substrings Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K

HDU 4455(dp)

题意:给定一个序列ai,个数为n.再给出一系列w:对于每个w,求序列中,所有长度为w的连续子串中的权值和,子串权值为子串中不同数的个数. 思路:动态规划,用dp[w]表示当前长度为w的时候的权值和.显然dp[1] = n; 如果求dp[2]的话,那么它可以由dp[1]推出来,首先它比dp[1]少了最后一个子序列,那么最后一个子序列的权值用num来表示,num[i]从后面开始数i位的权值,也就是不同的个数.然后在计算每个子序列多了一个多元素多增加的权值,这里用sum[i]表示长度两个相同元素最近距

hdu 4455 Substrings (DP 预处理思路)

Substrings Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1727    Accepted Submission(s): 518 Problem Description XXX has an array of length n. XXX wants to know that, for a given w, what is

HDU 4455 Substrings (2012年杭州赛区现场赛C题)

1.题目描述:点击打开链接 2.解题思路:本题利用dp解决.不过这个dp的思路的确比太容易想到.需要观察规律才能发现.我们可以从贡献值的角度考虑.以题目中给的样例来说明这种方法. 通过观察相邻两个w值,我们会发现一个事实:每个大区间都包含了小区间的解(这里的解即原题中的sum值).但是这还不够,观察图上标记为红色的数字,它们可以看做是上一个w值对应的区间多出来的新数字,如果我们可以算出这些红色数字的贡献值,那么我们就能得到当前w下的解.那么该如何计算呢? 继续观察后会发现,每次w增加1,区间个数