传送门: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
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
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
7 1 1 2 3 4 4 5 3 1 2 3 0
7 10 12
题目大意:
求长度为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;
}