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 the sum of the distinct elements’ number in all substrings of length w. For example, the array is { 1 1 2 3 4 4 5 } When w = 3, there are five substrings of length 3. They are (1,1,2),(1,2,3),(2,3,4),(3,4,4),(4,4,5)

The distinct elements’ number of those five substrings are 2,3,3,2,2.

So the sum of the distinct elements’ number should be 2+3+3+2+2 = 12

Input

There are several test cases.

Each test case starts with a positive integer n, the array length. The next line consists of n integers a1,a2…an, representing the elements of the array.

Then there is a line with an integer Q, the number of queries. At last Q lines follow, each contains one integer w, the substring length of query. The input data ends with n = 0 For all cases, 0<w<=n<=106, 0<=Q<=104, 0<= a1,a2…an <=106

Output

For each test case, your program should output exactly Q lines, the sum of the distinct number in all substrings of length w for each query.

Sample Input

7
1 1 2 3 4 4 5
3
1
2
3
0

Sample Output

7
10
12

1、
很明显,长度为1的答案为dp[1]=n;

2、
长度为2的为dp[2]=dp[1]+x-y=7+4-1=10;

X为增加的一个数和前边不同的个数,{1,1},{1,2},{2,3},{3,4},{4,4},{4,5} 为4;

Y为去掉的不足2的区间有几个不同数字,长度为1的最后一个区间{5},需要舍去,为1;

3、

长度为3的为dp[3]=dp[2]+x-y=10+4-2=12;

X为增加的一个数和前边不同的个数,{1,1,2},{1,2,3},{2,3,4},{3,4,4},{4,4,5}为4;

Y为去掉的不足3的区间有几个不同数字,长度为2的最后一个区间{4,5},需要舍去,为2;

所以,我们需要得到当前数字和它上次出现的位置差的大小。具体实现看代码。。

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 1000005
#define LL __int64
const int inf=0x1f1f1f1f;
int a[N],len[N],pre[N],vis[N],f[N];
LL dp[N];
int main()
{
    int i,n,m;
    while(scanf("%d",&n),n)
    {
        memset(pre,-1,sizeof(pre)); //记录一个值上次出现的位置
        memset(len,0,sizeof(len)); //len[i]:有几个间隔为i的数
        memset(dp,0,sizeof(dp));   //记录最终答案
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            len[i-pre[a[i]]]++;
            pre[a[i]]=i;
        }
        for(i=n-1;i>=0;i--)
            len[i]+=len[i+1];
        memset(f,0,sizeof(f));   //f[i]从后往前记录后i个数有几个不同值
        memset(vis,0,sizeof(vis));
        for(i=1;i<n;i++)
        {
            f[i]=f[i-1];
            if(!vis[a[n-i]])
            {
                vis[a[n-i]]=1;
                f[i]++;
            }
        }
        dp[1]=n;
        for(i=2;i<=n;i++)
            dp[i]=dp[i-1]+len[i]-f[i-1];
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&i);
            printf("%I64d\n",dp[i]);
        }

    }
    return 0;
}
时间: 2024-08-06 20:05:23

hdu 4455 Substrings (DP 预处理思路)的相关文章

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则是最后一个长度为

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

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

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 Substrings(线性dp,很有意思)

题意:这个题给你n个数,然后有q组询问,无修改,每次询问一个长度x,问你所有长度为x的区间价值加和是多少,区间的价值的计算是这样定义的,一个区间的价值就等于这个区间中不同数字的个数 思路:看了题解虽然理解了,但感觉还是很难想啊,原本这个题卡在了怎么把n2的降维成n的,这个题目也算是很经典的一个套路吧,疯狂预处理,把所需要的信息不断转化,疯狂降维预处理,然后达到On递推,感觉对于dp[i]和dp[i-1]之间的关系,单点贡献的那一部分不怎么容易想到,而且想到了单点贡献,也想不到怎么预处理,QAQ

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

【HDOJ】4455 Substrings

5000ms的时限,还挺长的.算法是DP.思路是找到ans[1..n]的结果,然后Query就容易做了.问题是怎么DP?考虑:1 1 2 3 4 4 5w=1: 7, 7 = 1 * 7w=2: 10,10 = |{1,1}|+|{1,2}|+|{2,3}|+|{3,4}|+|{4,4}|+|{4,5}|=1+2+2+2+1+2=10w=3: 12,  12 = |{1,1, 2}|+|{1,2, 3}|+|{2,3, 4}|+|{3,4, 5}|+|{4,4, 5}|...观察w=3如何在w=

hdu 4734 数位dp

http://acm.hdu.edu.cn/showproblem.php?pid=4734 Problem Description For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, plea