HDU

来源:互联网 发布:淘宝卡价格刷单权重 编辑:程序博客网 时间:2024/06/04 00:40

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4455

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 a 1,a 2…a n, 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<=10 6, 0<=Q<=10 4, 0<= a 1,a 2…a n <=10 6
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
71 1 2 3 4 4 531230
Sample Output
71012

题目大意:

求长度为w的连续区间中不同数字的个数的和。如题目example。

题解:

看到查询这么多应该考虑预处理一下。假设要求长度为len的区间的个数和。如果每次都暴力求解显然是不可能的。当len = 3时有(1,1,2)(1,2,3)(2,3,4)(3,4,4)(4,4,5),不妨把len-1的也列出来(因为暴力单独求解行不通,那就看看不同区间长度之间有什么联系吧)(1,1)(1,2)(2,3)(3,4)(4,4)(4,5)。我们可以发现长度为3的区间个数比长度为2的区间个数少一个,即数组最后的2个。加入长度为2的答案是X,长度为3的答案是Y,那么Y = X-(4,5)的不同的数字个数+(k=连续长度为3的有重复的数字的个数)。那么这个k是什么呢?先看一下数组a[i]={1,1,2,3,4,4,5}。记录每个数和自己相同且最近的距离。这样当我由长度2变为长度3的时候,这时候距离为2的就会在同一个区间中了,这时在剩下的距离数中减去距离为2的数就是还符合的距离数 = k(真的不知道该怎么表达了,具体看代码吧,结合由2到3的列式和数组中连续区间不能有重复的数字的想法应该就明白了)。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1e6+100;int a[maxn],vis[maxn],pos[maxn],f[maxn],sum[maxn];LL dp[maxn];int main(){    int n;    while(~scanf("%d",&n),n){        memset(pos,0,sizeof(pos));        memset(vis,0,sizeof(vis));        memset(f,0,sizeof(f));        memset(sum,0,sizeof(sum));        for(int i = 1;i<=n;i++){            scanf("%d",&a[i]);            sum[i-pos[a[i]]]++;            pos[a[i]] = i;        }        for(int i = 1;i<=n;i++){            if(!vis[a[n-i+1]]){                vis[a[n-i+1]] = 1;                f[i] = f[i-1]+1;            }            else f[i] = f[i-1];        }        int ans = n;        dp[1] = (LL)n;        for(int i = 2;i<=n;i++){            dp[i] = dp[i-1] - (LL)f[i-1];            ans -= sum[i-1];            dp[i] += (LL)ans;        }        int q ;        scanf("%d",&q);        while(q--){            int p;            scanf("%d",&p);            printf("%lld\n",dp[p]);        }    }    return 0;}